dnl This is m4 source.
dnl Process using m4 to produce 'C' language file.
dnl
dnl This file is supposed to be the same as PnetCDF's test_put.m4
dnl
dnl If you see this line, you can ignore the next one.
/* Do not edit this file. It is produced from the corresponding .m4 source */
dnl
/*
 *  Copyright (C) 2003, Northwestern University and Argonne National Laboratory
 *  See COPYRIGHT notice in top-level directory.
 */
/* $Id: test_put.m4 2672 2016-12-03 19:23:53Z wkliao $ */

dnl
dnl The command-line m4 macro "PNETCDF" is to differentiate PnetCDF and netCDF
dnl in terms of function prefix names (ncmpi_ vs. nc_), integer data types
dnl (MPI_Offset vs. size_t), and function name substrings for external data
dnl types.
dnl

#include "tests.h"

ifdef(`PNETCDF',,`dnl
#ifdef USE_PNETCDF
#include <pnetcdf.h>
#ifndef PNETCDF_VERSION_MAJOR
#error("PNETCDF_VERSION_MAJOR is not defined in pnetcdf.h")
#endif
#ifndef PNETCDF_VERSION_MINOR
#error("PNETCDF_VERSION_MAJOR is not defined in pnetcdf.h")
#endif
#endif')

define(`EXPECT_ERR',`error("expecting $1 but got %s",nc_err_code_name($2));')dnl

define(`IntType', `ifdef(`PNETCDF',`MPI_Offset',`size_t')')dnl
define(`PTRDType',`ifdef(`PNETCDF',`MPI_Offset',`ptrdiff_t')')dnl
define(`TestFunc',`ifdef(`PNETCDF',`test_ncmpi_put_$1',`test_nc_put_$1')')dnl
define(`APIFunc',` ifdef(`PNETCDF',`ncmpi_$1',`nc_$1')')dnl

define(`FileOpen', `ifdef(`PNETCDF',`ncmpi_open(comm, $1, $2, info, &ncid)', `file_open($1, $2, &ncid)')')dnl
define(`FileCreate',`ifdef(`PNETCDF',`ncmpi_create(comm, $1, $2, info, &ncid)', `file_create($1, $2, &ncid)')')dnl
define(`FileDelete',`ifdef(`PNETCDF',`ncmpi_delete($1,$2)',`nc_delete($1)')')dnl

define(`VarArgs',   `ifdef(`PNETCDF',`int numVars',`void')')dnl
define(`AttVarArgs',`ifdef(`PNETCDF',`int numGatts,int numVars',`void')')dnl

define(`PutVar1',`ifdef(`PNETCDF',`ncmpi_put_var1_$1_all',`nc_put_var1_$1')')dnl
define(`PutVar', `ifdef(`PNETCDF',`ncmpi_put_var_$1_all', `nc_put_var_$1')')dnl
define(`PutVara',`ifdef(`PNETCDF',`ncmpi_put_vara_$1_all',`nc_put_vara_$1')')dnl
define(`PutVars',`ifdef(`PNETCDF',`ncmpi_put_vars_$1_all',`nc_put_vars_$1')')dnl
define(`PutVarm',`ifdef(`PNETCDF',`ncmpi_put_varm_$1_all',`nc_put_varm_$1')')dnl
define(`PutAtt', `ifdef(`PNETCDF',`ncmpi_put_att_$1',`nc_put_att_$1')')dnl
define(`GetVar1',`ifdef(`PNETCDF',`ncmpi_get_var1_$1_all',`nc_get_var1_$1')')dnl
define(`DefVars',`ifdef(`PNETCDF',`def_vars($1,$2)',`def_vars($1)')')dnl

define(`PNETCDF_CHECK_ERANGE',`dnl
ifelse(`$1',`uchar',`ifdef(`PNETCDF',,`
`#'if !defined(USE_PNETCDF) || (PNETCDF_VERSION_MAJOR==1 && PNETCDF_VERSION_MINOR>=8)')',
       `$1',`schar',`ifdef(`PNETCDF',,`
`#'if defined(USE_PNETCDF) && PNETCDF_VERSION_MAJOR==1 && PNETCDF_VERSION_MINOR<7
                    else if (cdf_format < NC_FORMAT_CDF5) {
`#'else')')
                    else {
ifelse(`$1',`schar',`ifdef(`PNETCDF',,``#'endif')')
                        IF (err != NC_ERANGE)
                            EXPECT_ERR(NC_ERANGE, err)
                        ELSE_NOK
                    }
ifelse(`$1',`uchar',`ifdef(`PNETCDF',,``#'endif')')'
)dnl

undefine(`index')dnl
dnl dnl dnl
dnl
dnl Macros
dnl
dnl dnl dnl
dnl
dnl Upcase(str)
dnl
define(`Upcase',dnl
`dnl
translit($1, abcdefghijklmnopqrstuvwxyz, ABCDEFGHIJKLMNOPQRSTUVWXYZ)')dnl
dnl dnl dnl
dnl
dnl NCT_ITYPE(type)
dnl
define(`NCT_ITYPE',    ``NCT_'Upcase($1)')dnl
define(`NC_TYPE',      ``NC_'Upcase($1)')dnl
define(`X_MIN',        ``X_'Upcase($1)_MIN')dnl
define(`X_MAX',        ``X_'Upcase($1)_MAX')dnl
dnl

define(`CheckText', `ifelse(`$1',`text', , `== (NCT_ITYPE($1) == NCT_TEXT)')')dnl
define(`IfCheckTextChar', `ifelse(`$1',`text', `if ($2 != NC_CHAR)')')dnl
define(`CheckNumRange',
       `ifelse(`$1',`text', `1',
               `inRange3(cdf_format, (double)$2,$3,NCT_ITYPE($1)) && ($2 >= $1_min && $2 <= $1_max)')')dnl
define(`CheckRange',
       `ifelse(`$1',`text', `0', `($2 >= $1_min && $2 <= $1_max)')')dnl
define(`CheckRange3',
       `ifelse(`$1',`text', `1',
               `inRange3(cdf_format, (double)$2,$3,NCT_ITYPE($1))')')dnl

dnl HASH(TYPE)
dnl
define(`HASH',dnl
`dnl
/*
 *  ensure hash value within range for internal TYPE
 */
$1
hash_$1(const int       cdf_format,
        const nc_type   type,
        const int       rank,
        const IntType  *index,
        const nct_itype itype)
{
    double value;

    value = hash4(cdf_format, type, rank, index, itype);
    ifelse(`$1',`text',`return (text)value;',`
    if (value > $1_max) return $1_max;
    else if (value < $1_min) return $1_min;
    else return ($1)value;')
}
')dnl

HASH(text)
HASH(uchar)
HASH(schar)
HASH(short)
HASH(int)
HASH(long)
HASH(float)
HASH(double)
HASH(ushort)
HASH(uint)
HASH(longlong)
HASH(ulonglong)


dnl CHECK_VARS(TYPE)
dnl
define(`CHECK_VARS',dnl
`dnl
/*
 *  check all vars in file which are (text/numeric) compatible with TYPE
 */
int
check_vars_$1(const char *filename, int numVars)
{
    int i, d, err, ncid, cdf_format, ndims;
    int canConvert;   /* Both text or both numeric */
    int nok = 0;      /* count of valid comparisons */
    int dimids[MAX_RANK];
    nc_type datatype;
    char name[NC_MAX_NAME];
    IntType j, length, index[MAX_RANK];
    double expect;
    $1 value;

    err = FileOpen(filename, NC_NOWRITE);
    IF (err != NC_NOERR) error("open: %s", APIFunc(strerror)(err));

    err = APIFunc(inq_format)(ncid, &cdf_format);
    IF (err != NC_NOERR) error("inq_format: %s", APIFunc(strerror)(err));

    for (i = 0; i < numVars; i++) {
        canConvert = (var_type[i] == NC_CHAR) CheckText($1);
        if (!canConvert) continue;

        err = APIFunc(inq_var)(ncid, i, name, &datatype, &ndims, dimids, NULL);
        IF (err != NC_NOERR)
            error("inq_var: %s", APIFunc(strerror)(err));
        IF (strcmp(name, var_name[i]) != 0)
            error("Unexpected var_name");
        IF (datatype != var_type[i])
            error("Unexpected type");
        IF (ndims != var_rank[i])
            error("Unexpected rank");
        for (j = 0; j < ndims; j++) {
            err = APIFunc(inq_dim)(ncid, dimids[j], 0, &length);
            IF (err != NC_NOERR)
                error("inq_dim: %s", APIFunc(strerror)(err));
            IF (length != var_shape[i][j])
                error("Unexpected shape");
        }
        for (j = 0; j < var_nels[i]; j++) {
            err = toMixedBase(j, var_rank[i], var_shape[i], index);
            IF (err != 0) error("error in toMixedBase");
            expect = hash4(cdf_format, var_type[i], var_rank[i], index,
                           NCT_ITYPE($1));
            err = GetVar1($1)(ncid, i, index, &value);
            if (CheckNumRange($1, expect, datatype)) {
                IF (err != NC_NOERR) {
                    error("GetVar1($1): %s", APIFunc(strerror)(err));
                } else {
                    ifelse(`$1', `uchar', `
                    /* In put_vars(), PutVara(double)() is used to write
                     * variables of type NC_BYTE to files. For uchar APIs,
                     * NC_BYTE variables are treated as unsigned for CDF-1 and 2
                     * formats. Thus, we skip the equal test for out-of-bound
                     * values below for uchar APIs.
                     */
                    if (cdf_format < NC_FORMAT_CDF5 &&
                        var_type[i] == NC_BYTE && expect > schar_max)
                        continue;')
                    IF (!equal((double)value,expect,var_type[i],NCT_ITYPE($1))){
                        error("Var value read not that expected");
                        if (verbose) {
                            error("\n");
                            error("varid: %d, ", i);
                            error("var_name: %s, ", var_name[i]);
                            error("var_type: %s, ", s_nc_type(var_type[i]));
                            error("index:");
                            for (d = 0; d < var_rank[i] && d < MAX_RANK; d++)
                                error(" %d", index[d]);
                            error(", expect: %g, ", expect);
                            error("got: %g", (double) value);
                        }
                    } else {
                        ++nok;
                    }
                }
            }
        }
    }
    err = APIFunc(close)(ncid);
    IF (err != NC_NOERR)
        error("close: %s", APIFunc(strerror)(err));
    return nok;
}
')dnl

CHECK_VARS(text)
CHECK_VARS(uchar)
CHECK_VARS(schar)
CHECK_VARS(short)
CHECK_VARS(int)
CHECK_VARS(long)
CHECK_VARS(float)
CHECK_VARS(double)
CHECK_VARS(ushort)
CHECK_VARS(uint)
CHECK_VARS(longlong)
CHECK_VARS(ulonglong)


dnl CHECK_ATTS(TYPE)
dnl
define(`CHECK_ATTS',dnl
`dnl
/*
 *  for _text tests, check all attributes in file which are of text type
 *  Note no NC_ERANGE check for text attributes as text is not convertible to
 *  any other numerical data types (i.e. NC_ECHAR)
 *
 *  for other tests, check all numerical attributes in file against values
 *  outside range of type $1
 */
int
check_atts_$1(int ncid, int numGatts, int numVars)
{
    int i, j, cdf_format, err;
    int canConvert;      /* Both text or both numeric */
    int nok = 0;         /* count of valid comparisons */
    IntType k, length, ndx[1];
    nc_type datatype;
    IntType nInExtRange;  /* number values within external range */
    IntType nInIntRange;  /* number values within internal range */
    double expect[MAX_NELS];
    $1 value[MAX_NELS];

    err = APIFunc(inq_format)(ncid, &cdf_format);
    IF (err != NC_NOERR)
        error("inq_format: %s", APIFunc(strerror)(err));

    for (i = -1; i < numVars; i++) {
        for (j = 0; j < NATTS(i); j++) {
            canConvert = (ATT_TYPE(i,j) == NC_CHAR) CheckText($1);
            if (!canConvert) continue;

            err = APIFunc(inq_att)(ncid, i, ATT_NAME(i,j), &datatype, &length);
            IF (err != NC_NOERR)
                error("inq_att: %s", APIFunc(strerror)(err));
            IF (datatype != ATT_TYPE(i,j))
                error("inq_att: unexpected type");
            IF (length != ATT_LEN(i,j))
                error("inq_att: unexpected length");
            assert(length <= MAX_NELS);
            nInIntRange = nInExtRange = 0;
            for (k = 0; k < length; k++) {
                ndx[0] = k;
                expect[k] = hash4(cdf_format, datatype, -1, ndx, NCT_ITYPE($1));
                if (inRange3(cdf_format, expect[k], datatype, NCT_ITYPE($1))) {
                    ++nInExtRange;
                    if (CheckRange($1, expect[k]))
                        ++nInIntRange;
                }
            }
            err = APIFunc(get_att_$1)(ncid, i, ATT_NAME(i,j), value);
            if (nInExtRange == length && nInIntRange == length) {
                IF (err != NC_NOERR)
                    EXPECT_ERR(NC_NOERR, err)
            } else {
                IF (err != NC_NOERR && err != NC_ERANGE)
                    EXPECT_ERR(NC_NOERR or NC_ERANGE, err)
            }
            for (k = 0; k < length; k++) {
                if (CheckNumRange($1, expect[k], datatype)) {
                    ifelse(`$1', `uchar', `
                    /* In put_vars(), PutVara(double)() is used to write
                     * variables of type NC_BYTE to files. For uchar APIs,
                     * NC_BYTE variables are treated as unsigned for CDF-1 and 2
                     * formats. Thus, we skip the equal test for out-of-bound
                     * values below for uchar APIs.
                     */
                    if (cdf_format < NC_FORMAT_CDF5 &&
                        ATT_TYPE(i,j) == NC_BYTE && expect[k] > schar_max)
                        continue;')
                    IF (!equal((double)value[k],expect[k],datatype,NCT_ITYPE($1))) {
                        error("att. value read not that expected");
                        if (verbose) {
                            error("\n");
                            error("varid: %d, ", i);
                            error("att_name: %s, ", ATT_NAME(i,j));
                            error("att_type: %s, ", s_nc_type(ATT_TYPE(i,j)));
                            error("element number: %d ", k);
                            error("expect: %g, ", expect[k]);
                            error("got: %g", (double) value[k]);
                        }
                    } else {
                        nok++;
                    }
                }
            }
        }
    }
    return nok;
}
')dnl

CHECK_ATTS(text)
CHECK_ATTS(uchar)
CHECK_ATTS(schar)
CHECK_ATTS(short)
CHECK_ATTS(int)
CHECK_ATTS(long)
CHECK_ATTS(float)
CHECK_ATTS(double)
CHECK_ATTS(ushort)
CHECK_ATTS(uint)
CHECK_ATTS(longlong)
CHECK_ATTS(ulonglong)


dnl TEST_NC_PUT_VAR1(TYPE)
dnl
define(`TEST_NC_PUT_VAR1',dnl
`dnl
int
TestFunc(var1)_$1(VarArgs)
{
    int i, err, ncid, cdf_format, nok=0;
    int canConvert;      /* Both text or both numeric */
    IntType j, index[MAX_RANK];
    $1 value[1];

    err = FileCreate(scratch, NC_CLOBBER);
    IF (err != NC_NOERR) {
        error("create: %s", APIFunc(strerror)(err));
        return nok;
    }

    err = APIFunc(inq_format)(ncid, &cdf_format);
    IF (err != NC_NOERR)
        error("inq_format: %s", APIFunc(strerror)(err));

    def_dims(ncid);
    DefVars(ncid, numVars);

    err = APIFunc(enddef)(ncid);
    IF (err != NC_NOERR)
        error("enddef: %s", APIFunc(strerror)(err));

    /* check if can detect a bad file ID */
    err = PutVar1($1)(BAD_ID, 0, NULL, NULL);
    IF (err != NC_EBADID)
        EXPECT_ERR(NC_EBADID, err)
    ELSE_NOK

    /* check if can detect a bad variable ID */
    err = PutVar1($1)(ncid, BAD_VARID, NULL, NULL);
    IF (err != NC_ENOTVAR)
        EXPECT_ERR(NC_ENOTVAR, err)
    ELSE_NOK

    for (i = 0; i < numVars; i++) {
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);

        value[0] = 5;  /* reset to a value within bounds */

        /* check if can detect a bad file ID */
        err = PutVar1($1)(BAD_ID, i, NULL, value);
        IF (err != NC_EBADID)
            EXPECT_ERR(NC_EBADID, err)
        ELSE_NOK

        canConvert = (var_type[i] == NC_CHAR) CheckText($1);

ifdef(`PNETCDF',`dnl
        /* for non-scalar variables, argument start cannot be NULL */
        err = PutVar1($1)(ncid, i, NULL, value);
        if (!canConvert) {
            IF (err != NC_ECHAR) EXPECT_ERR(NC_ECHAR, err)
        }
        else if (var_rank[i] == 0) {
            IF (err != NC_NOERR) EXPECT_ERR(NC_NOERR, err)
        }
        else IF (err != NC_EINVALCOORDS) {
            EXPECT_ERR(NC_EINVALCOORDS, err)
        }
        ELSE_NOK
')dnl

        /* test NC_EINVALCOORDS */
        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) index[j] = 0;

        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
            if (var_dimid[i][j] == RECDIM) continue; /* skip record dim */
            index[j] = var_shape[i][j];     /* out of boundary check */
            err = PutVar1($1)(ncid, i, index, value);
            if (!canConvert) {
                IF (err != NC_ECHAR)
                    EXPECT_ERR(NC_ECHAR, err)
                ELSE_NOK
                index[j] = 0;
                continue;
            }
            IF (err != NC_EINVALCOORDS)
                EXPECT_ERR(NC_EINVALCOORDS, err)
            ELSE_NOK
            index[j] = 0;
        }

        for (j = 0; j < var_nels[i]; j++) {
            err = toMixedBase(j, var_rank[i], var_shape[i], index);
            IF (err != 0) error("error in toMixedBase");
            value[0] = hash_$1(cdf_format, var_type[i], var_rank[i], index,
                               NCT_ITYPE($1));
            err = PutVar1($1)(ncid, i, index, value);
            if (canConvert) {
                if (CheckRange3($1, value[0], var_type[i])) {
                    IF (err != NC_NOERR)
                        EXPECT_ERR(NC_NOERR, err)
                    ELSE_NOK
                }
                PNETCDF_CHECK_ERANGE($1)
            } else {
                IF (err != NC_ECHAR)
                    EXPECT_ERR(NC_ECHAR, err)
                ELSE_NOK
            }
        }
    }

    err = APIFunc(close)(ncid);
    IF (err != NC_NOERR)
        error("close: %s", APIFunc(strerror)(err));

    nok += check_vars_$1(scratch, numVars);

    err = FileDelete(scratch, info);
    IF (err != NC_NOERR)
        error("delete file %s failed", scratch);
    return nok;
}
')dnl

TEST_NC_PUT_VAR1(text)
TEST_NC_PUT_VAR1(uchar)
TEST_NC_PUT_VAR1(schar)
TEST_NC_PUT_VAR1(short)
TEST_NC_PUT_VAR1(int)
TEST_NC_PUT_VAR1(long)
TEST_NC_PUT_VAR1(float)
TEST_NC_PUT_VAR1(double)
TEST_NC_PUT_VAR1(ushort)
TEST_NC_PUT_VAR1(uint)
TEST_NC_PUT_VAR1(longlong)
TEST_NC_PUT_VAR1(ulonglong)


dnl TEST_NC_PUT_VAR(TYPE)
dnl
define(`TEST_NC_PUT_VAR',dnl
`dnl
int
TestFunc(var)_$1(VarArgs)
{
    int i, err, ncid, varid, cdf_format, nok=0;
    int canConvert;        /* Both text or both numeric */
    int allInExtRange;     /* all values within external range? */
    IntType j, index[MAX_RANK];
    $1 value[MAX_NELS];

    err = FileCreate(scratch, NC_CLOBBER);
    IF (err != NC_NOERR) {
        error("create: %s", APIFunc(strerror)(err));
        return nok;
    }

    err = APIFunc(inq_format)(ncid, &cdf_format);
    IF (err != NC_NOERR)
        error("inq_format: %s", APIFunc(strerror)(err));

    def_dims(ncid);
    DefVars(ncid, numVars);

    err = APIFunc(enddef)(ncid);
    IF (err != NC_NOERR)
        error("enddef: %s", APIFunc(strerror)(err));

    /* check if can detect a bad file ID */
    err = PutVar($1)(BAD_ID, 0, NULL);
    IF (err != NC_EBADID)
        EXPECT_ERR(NC_EBADID, err)
    ELSE_NOK

    /* check if can detect a bad variable ID */
    err = PutVar($1)(ncid, BAD_VARID, NULL);
    IF (err != NC_ENOTVAR)
        EXPECT_ERR(NC_ENOTVAR, err)
    ELSE_NOK

    for (i = 0; i < numVars; i++) {
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);

        if (var_dimid[i][0] == RECDIM) continue; /* fixed-size variables only */

        value[0] = 5;  /* reset to a value within bounds */

        /* check if can detect a bad file ID */
        err = PutVar($1)(BAD_ID, i, value);
        IF (err != NC_EBADID)
            EXPECT_ERR(NC_EBADID, err)
        ELSE_NOK

        canConvert = (var_type[i] == NC_CHAR) CheckText($1);

        for (allInExtRange = 1, j = 0; j < var_nels[i]; j++) {
            err = toMixedBase(j, var_rank[i], var_shape[i], index);
            IF (err != 0) error("error in toMixedBase");
            value[j]= hash_$1(cdf_format,var_type[i], var_rank[i], index,
                              NCT_ITYPE($1));
            IfCheckTextChar($1, var_type[i])
                allInExtRange &= inRange3(cdf_format, (double)value[j],
                                          var_type[i], NCT_ITYPE($1));
        }
        err = PutVar($1)(ncid, i, value);
        if (canConvert) {
            if (allInExtRange) {
                IF (err != NC_NOERR)
                    EXPECT_ERR(NC_NOERR, err)
                ELSE_NOK
            }
            PNETCDF_CHECK_ERANGE($1)
        } else { /* should flag wrong type even if nothing to write */
            IF (err != NC_ECHAR)
                EXPECT_ERR(NC_ECHAR, err)
            ELSE_NOK
        }
    }

    /* Preceding has written nothing for record variables, now try */
    /* again with more than 0 records */

    /* Write record number NRECS to force writing of preceding records */
    /* Assumes variable cr is char vector with UNLIMITED dimension */
    err = APIFunc(inq_varid)(ncid, "cr", &varid);
    IF (err != NC_NOERR)
        error("inq_varid: %s", APIFunc(strerror)(err));
    index[0] = NRECS-1;
    err = PutVar1(text)(ncid, varid, index, "x");
    IF (err != NC_NOERR)
        error("put_var1_text: %s", APIFunc(strerror)(err));

    for (i = 0; i < numVars; i++) {
        if (var_dimid[i][0] != RECDIM) continue; /* only record variables here */

        canConvert = (var_type[i] == NC_CHAR) CheckText($1);

        for (allInExtRange = 1, j = 0; j < var_nels[i]; j++) {
            err = toMixedBase(j, var_rank[i], var_shape[i], index);
            IF (err != 0) error("error in toMixedBase");
            value[j]= hash_$1(cdf_format,var_type[i], var_rank[i], index,
                              NCT_ITYPE($1));
            IfCheckTextChar($1, var_type[i])
                allInExtRange &= inRange3(cdf_format, (double)value[j],
                                          var_type[i], NCT_ITYPE($1));
        }
        err = PutVar($1)(ncid, i, value);
        if (canConvert) {
            if (allInExtRange) {
                IF (err != NC_NOERR)
                    EXPECT_ERR(NC_NOERR, err)
                ELSE_NOK
            } else {
                IF (err != NC_ERANGE)
                    EXPECT_ERR(NC_ERANGE, err)
                ELSE_NOK
            }
        } else {
            IF (err != NC_ECHAR)
                EXPECT_ERR(NC_ECHAR, err)
            ELSE_NOK
        }
    }

    err = APIFunc(close)(ncid);
    IF (err != NC_NOERR)
        error("close: %s", APIFunc(strerror)(err));

    nok += check_vars_$1(scratch, numVars);

    err = FileDelete(scratch, info);
    IF (err != NC_NOERR)
        error("delete file %s failed", scratch);
    return nok;
}
')dnl

TEST_NC_PUT_VAR(text)
TEST_NC_PUT_VAR(uchar)
TEST_NC_PUT_VAR(schar)
TEST_NC_PUT_VAR(short)
TEST_NC_PUT_VAR(int)
TEST_NC_PUT_VAR(long)
TEST_NC_PUT_VAR(float)
TEST_NC_PUT_VAR(double)
TEST_NC_PUT_VAR(ushort)
TEST_NC_PUT_VAR(uint)
TEST_NC_PUT_VAR(longlong)
TEST_NC_PUT_VAR(ulonglong)


dnl TEST_NC_PUT_VARA(TYPE)
dnl
define(`TEST_NC_PUT_VARA',dnl
`dnl
int
TestFunc(vara)_$1(VarArgs)
{
    int i, k, d, err, nslabs, ncid, cdf_format, nok=0;
    int canConvert;        /* Both text or both numeric */
    int allInExtRange;     /* all values within external range? */
    IntType j, nels;
    IntType start[MAX_RANK], edge[MAX_RANK];
    IntType mid[MAX_RANK], index[MAX_RANK];
    $1 value[MAX_NELS];

    for(j = 0; j < MAX_RANK; j++) {
          start[j] = 0;
          edge[j] = 0;
          mid[j] = 0;
          index[j] = 0;
    }

    err = FileCreate(scratch, NC_CLOBBER);
    IF (err != NC_NOERR) {
        error("create: %s", APIFunc(strerror)(err));
        return nok;
    }

    err = APIFunc(inq_format)(ncid, &cdf_format);
    IF (err != NC_NOERR)
        error("inq_format: %s", APIFunc(strerror)(err));

    def_dims(ncid);
    DefVars(ncid, numVars);

    err = APIFunc(enddef)(ncid);
    IF (err != NC_NOERR)
        error("enddef: %s", APIFunc(strerror)(err));

    /* check if can detect a bad file ID */
    err = PutVara($1)(BAD_ID, 0, NULL, NULL, NULL);
    IF (err != NC_EBADID)
        EXPECT_ERR(NC_EBADID, err)
    ELSE_NOK

    /* check if can detect a bad variable ID */
    err = PutVara($1)(ncid, BAD_VARID, NULL, NULL, NULL);
    IF (err != NC_ENOTVAR)
        EXPECT_ERR(NC_ENOTVAR, err)
    ELSE_NOK

    for (i = 0; i < numVars; i++) {
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);

        value[0] = 5; /* reset to a value within bounds */

        /* check if can detect a bad file ID */
        err = PutVara($1)(BAD_ID, i, NULL, NULL, value);
        IF (err != NC_EBADID)
            EXPECT_ERR(NC_EBADID, err)
        ELSE_NOK

        canConvert = (var_type[i] == NC_CHAR) CheckText($1);

        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
            start[j] = 0;
            edge[j] = 1;
        }

ifdef(`PNETCDF',`dnl
        /* for non-scalar variables, argument start cannot be NULL */
        err = PutVara($1)(ncid, i, NULL, NULL, value);
        if (!canConvert) {
            IF (err != NC_ECHAR) EXPECT_ERR(NC_ECHAR, err)
        }
        else if (var_rank[i] == 0) {
            IF (err != NC_NOERR) EXPECT_ERR(NC_NOERR, err)
        }
        else IF (err != NC_EINVALCOORDS) {
            EXPECT_ERR(NC_EINVALCOORDS, err)
        }
        ELSE_NOK

        /* for non-scalar variables, argument count cannot be NULL */
        err = PutVara($1)(ncid, i, start, NULL, value);
        if (!canConvert) {
            IF (err != NC_ECHAR) EXPECT_ERR(NC_ECHAR, err)
        }
        else if (var_rank[i] == 0) {
            IF (err != NC_NOERR) EXPECT_ERR(NC_NOERR, err)
        }
        else IF (err != NC_EEDGE) {
            EXPECT_ERR(NC_EEDGE, err)
        }
        ELSE_NOK
')dnl

        /* first test when edge[*] > 0 */
        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
            if (var_dimid[i][j] == RECDIM) continue; /* skip record dim */
            start[j] = var_shape[i][j];
            err = PutVara($1)(ncid, i, start, edge, value);
            if (!canConvert) {
                IF (err != NC_ECHAR)
                    EXPECT_ERR(NC_ECHAR, err)
                ELSE_NOK
                start[j] = 0;
                continue;
            }
            IF (err != NC_EINVALCOORDS)
                EXPECT_ERR(NC_EINVALCOORDS, err)
            ELSE_NOK
            start[j] = 0;
            edge[j] = var_shape[i][j] + 1;
            err = PutVara($1)(ncid, i, start, edge, value);
            IF (err != NC_EEDGE)
                EXPECT_ERR(NC_EEDG, err)
            ELSE_NOK
            edge[j] = 1;
        }

        /* Check correct error returned when nothing to put, when edge[*]==0 */
        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) edge[j] = 0;

        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
            if (var_dimid[i][j] == RECDIM) continue; /* skip record dim */
            start[j] = var_shape[i][j];
            err = PutVara($1)(ncid, i, start, edge, value);
            if (!canConvert) {
                IF (err != NC_ECHAR)
                    EXPECT_ERR(NC_ECHAR, err)
                ELSE_NOK
                start[j] = 0;
                continue;
            }
            IF (err != NC_NOERR) /* allowed when edge[j]==0 */
                EXPECT_ERR(NC_NOERR, err)
            ELSE_NOK
            start[j] = var_shape[i][j]+1; /* out of boundary check */
            err = PutVara($1)(ncid, i, start, edge, value);
            IF (err != NC_EINVALCOORDS)
                EXPECT_ERR(NC_EINVALCOORDS, err)
            ELSE_NOK
            start[j] = 0;
        }
        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) edge[j] = 1;

        /* Choose a random point dividing each dim into 2 parts */
        /* Put 2^rank (nslabs) slabs so defined */
        nslabs = 1;
        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
            mid[j] = roll( var_shape[i][j] );
            nslabs *= 2;
        }
        /* bits of k determine whether to put lower or upper part of dim */
        for (k = 0; k < nslabs; k++) {
            nels = 1;
            for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
                if ((k >> j) & 1) {
                    start[j] = 0;
                    edge[j] = mid[j];
                } else {
                    start[j] = mid[j];
                    edge[j] = var_shape[i][j] - mid[j];
                }
                nels *= edge[j];
            }

            for (allInExtRange = 1, j = 0; j < nels; j++) {
                err = toMixedBase(j, var_rank[i], edge, index);
                IF (err != 0) error("error in toMixedBase");
                for (d = 0; d < var_rank[i] && d < MAX_RANK; d++)
                    index[d] += start[d];
                value[j]= hash_$1(cdf_format,var_type[i], var_rank[i], index,
                                  NCT_ITYPE($1));
                IfCheckTextChar($1, var_type[i])
                    allInExtRange &= inRange3(cdf_format, (double)value[j],
                                              var_type[i], NCT_ITYPE($1));
            }
            err = PutVara($1)(ncid, i, start, edge, value);
            if (canConvert) {
                if (allInExtRange) {
                    IF (err != NC_NOERR)
                        EXPECT_ERR(NC_NOERR, err)
                    ELSE_NOK
                }
                PNETCDF_CHECK_ERANGE($1)
            } else {
                IF (err != NC_ECHAR)
                    EXPECT_ERR(NC_ECHAR, err)
                ELSE_NOK
            }
        }
    }

    err = APIFunc(close)(ncid);
    IF (err != NC_NOERR)
        error("close: %s", APIFunc(strerror)(err));

    nok += check_vars_$1(scratch, numVars);

    err = FileDelete(scratch, info);
    IF (err != NC_NOERR)
        error("delete file %s failed", scratch);
    return nok;
}
')dnl

TEST_NC_PUT_VARA(text)
TEST_NC_PUT_VARA(uchar)
TEST_NC_PUT_VARA(schar)
TEST_NC_PUT_VARA(short)
TEST_NC_PUT_VARA(int)
TEST_NC_PUT_VARA(long)
TEST_NC_PUT_VARA(float)
TEST_NC_PUT_VARA(double)
TEST_NC_PUT_VARA(ushort)
TEST_NC_PUT_VARA(uint)
TEST_NC_PUT_VARA(longlong)
TEST_NC_PUT_VARA(ulonglong)


dnl TEST_NC_PUT_VARS(TYPE)
dnl
define(`TEST_NC_PUT_VARS',dnl
`dnl
int
TestFunc(vars)_$1(VarArgs)
{
    int i, k, d, err, nslabs, ncid, cdf_format, nok=0;
    int canConvert;     /* Both text or both numeric */
    int allInExtRange;  /* all values within external range? */
    IntType j, m, nels;
    IntType start[MAX_RANK], edge[MAX_RANK], index[MAX_RANK];
    IntType index2[MAX_RANK], mid[MAX_RANK], count[MAX_RANK];
    IntType sstride[MAX_RANK];
    PTRDType nstarts;   /* number of different starts */
    PTRDType stride[MAX_RANK];
    $1 value[MAX_NELS];

    for(j = 0; j < MAX_RANK; j++) {
          start[j] = 0;
          edge[j] = 0;
          mid[j] = 0;
          index[j] = 0;
          index2[j] = 0;
          count[j] = 0;
          sstride[j] = 1;
          stride[j] = 1;
    }

    err = FileCreate(scratch, NC_CLOBBER);
    IF (err != NC_NOERR) {
        error("create: %s", APIFunc(strerror)(err));
        return nok;
    }

    err = APIFunc(inq_format)(ncid, &cdf_format);
    IF (err != NC_NOERR)
        error("inq_format: %s", APIFunc(strerror)(err));

    def_dims(ncid);
    DefVars(ncid, numVars);

    err = APIFunc(enddef)(ncid);
    IF (err != NC_NOERR)
        error("enddef: %s", APIFunc(strerror)(err));

    /* check if can detect a bad file ID */
    err = PutVars($1)(BAD_ID, 0, NULL, NULL, NULL, NULL);
    IF (err != NC_EBADID)
        EXPECT_ERR(NC_EBADID, err)
    ELSE_NOK

    /* check if can detect a bad variable ID */
    err = PutVars($1)(ncid, BAD_VARID, NULL, NULL, NULL, NULL);
    IF (err != NC_ENOTVAR)
        EXPECT_ERR(NC_ENOTVAR, err)
    ELSE_NOK

    for (i = 0; i < numVars; i++) {
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);

        value[0] = 5; /* reset to a value within bounds */

        /* check if can detect a bad file ID */
        err = PutVars($1)(BAD_ID, i, NULL, NULL, NULL, value);
        IF (err != NC_EBADID)
            EXPECT_ERR(NC_EBADID, err)
        ELSE_NOK

        canConvert = (var_type[i] == NC_CHAR) CheckText($1);

        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
            start[j] = 0;
            edge[j] = 1;
            stride[j] = 1;
        }
ifdef(`PNETCDF',`dnl
        /* for non-scalar variables, argument start cannot be NULL */
        err = PutVars($1)(ncid, i, NULL, NULL, NULL, value);
        if (!canConvert) {
            IF (err != NC_ECHAR) EXPECT_ERR(NC_ECHAR, err)
        }
        else if (var_rank[i] == 0) { /* scalar variable */
            IF (err != NC_NOERR) EXPECT_ERR(NC_NOERR, err)
        }
        else IF (err != NC_EINVALCOORDS) {
            EXPECT_ERR(NC_EINVALCOORDS, err)
        }
        ELSE_NOK

        /* for non-scalar variables, argument count cannot be NULL */
        err = PutVars($1)(ncid, i, start, NULL, NULL, value);
        if (!canConvert) {
            IF (err != NC_ECHAR) EXPECT_ERR(NC_ECHAR, err)
        }
        else if (var_rank[i] == 0) { /* scalar variable */
            IF (err != NC_NOERR) EXPECT_ERR(NC_NOERR, err)
        }
        else IF (err != NC_EEDGE) {
            EXPECT_ERR(NC_EEDGE, err)
        }
        ELSE_NOK
')dnl

        /* first test when edge[*] > 0 */
        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
            if (var_dimid[i][j] == RECDIM) continue; /* skip record dim */
            start[j] = var_shape[i][j];   /* out of boundary check */
            err = PutVars($1)(ncid, i, start, edge, stride, value);
            if (!canConvert) {
                IF (err != NC_ECHAR)
                    EXPECT_ERR(NC_ECHAR, err)
                ELSE_NOK
                start[j] = 0;
                continue;
            }
            IF (err != NC_EINVALCOORDS)
                EXPECT_ERR(NC_EINVALCOORDS, err)
            ELSE_NOK
            start[j] = 0;
            edge[j] = var_shape[i][j] + 1;
            err = PutVars($1)(ncid, i, start, edge, stride, value);
            IF (err != NC_EEDGE)
                EXPECT_ERR(NC_EEDGE, err)
            ELSE_NOK
            edge[j] = 1;
            stride[j] = 0;
            err = PutVars($1)(ncid, i, start, edge, stride, value);
            IF (err != NC_ESTRIDE)
                EXPECT_ERR(NC_ESTRIDE, err)
            ELSE_NOK
            stride[j] = 1;
        }
        /* Check correct error returned even when nothing to put */
        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) edge[j] = 0;

        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
            if (var_dimid[i][j] == RECDIM) continue; /* skip record dim */
            start[j] = var_shape[i][j];
            err = PutVars($1)(ncid, i, start, edge, stride, value);
            if (!canConvert) {
                IF (err != NC_ECHAR)
                    EXPECT_ERR(NC_ECHAR, err)
                ELSE_NOK
                start[j] = 0;
                continue;
            }
            IF (err != NC_NOERR) /* allowed when edge[j]==0 */
                EXPECT_ERR(NC_NOERR, err)
            ELSE_NOK
            start[j] = var_shape[i][j]+1; /* out of boundary check */
            err = PutVars($1)(ncid, i, start, edge, stride, value);
            IF (err != NC_EINVALCOORDS)
                EXPECT_ERR(NC_EINVALCOORDS, err)
            ELSE_NOK
            start[j] = 0;
        }
        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) edge[j] = 1;

        /* Choose a random point dividing each dim into 2 parts */
        /* Put 2^rank (nslabs) slabs so defined */
        nslabs = 1;
        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
            mid[j] = roll( var_shape[i][j] );
            nslabs *= 2;
        }
        /* bits of k determine whether to put lower or upper part of dim */
        /* choose random stride from 1 to edge */
        for (k = 0; k < nslabs; k++) {
            nstarts = 1;
            for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
                if ((k >> j) & 1) {
                    start[j] = 0;
                    edge[j] = mid[j];
                } else {
                    start[j] = mid[j];
                    edge[j] = var_shape[i][j] - mid[j];
                }
                sstride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
                stride[j] = (PTRDType)sstride[j];
                nstarts *= stride[j];
            }
            for (m = 0; m < nstarts; m++) {
                err = toMixedBase(m, var_rank[i], sstride, index);
                IF (err != 0) error("error in toMixedBase");
                nels = 1;
                for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
                    count[j] = 1 + (edge[j] - index[j] - 1) / ( (IntType)stride[j] == 0 ? 1 : (IntType)stride[j]);
                    nels *= count[j];
                    index[j] += start[j];
                }
                /* Random choice of forward or backward */
/* TODO
                if ( roll(2) ) {
                    for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
                        index[j] += (count[j] - 1) * (IntType)stride[j];
                        stride[j] = -stride[j];
                    }
                }
*/
                for (allInExtRange = 1, j = 0; j < nels; j++) {
                    err = toMixedBase(j, var_rank[i], count, index2);
                    IF (err != 0) error("error in toMixedBase");
                    for (d = 0; d < var_rank[i] && d < MAX_RANK; d++)
                        index2[d] = index[d] + index2[d] * (IntType)stride[d];
                    value[j] = hash_$1(cdf_format,var_type[i], var_rank[i],
                                       index2, NCT_ITYPE($1));
                    IfCheckTextChar($1, var_type[i])
                        allInExtRange &= inRange3(cdf_format, (double)value[j],
                                                  var_type[i], NCT_ITYPE($1));
                }
                err = PutVars($1)(ncid, i, index, count, stride, value);
                if (canConvert) {
                    if (allInExtRange) {
                        IF (err != NC_NOERR)
                            EXPECT_ERR(NC_NOERR, err)
                        ELSE_NOK
                    }
                    PNETCDF_CHECK_ERANGE($1)
                } else {
                    IF (err != NC_ECHAR)
                        EXPECT_ERR(NC_ECHAR, err)
                    ELSE_NOK
                }
            }
        }
    }

    err = APIFunc(close)(ncid);
    IF (err != NC_NOERR)
        error("close: %s", APIFunc(strerror)(err));

    nok += check_vars_$1(scratch, numVars);

    err = FileDelete(scratch, info);
    IF (err != NC_NOERR)
        error("delete file %s failed", scratch);
    return nok;
}
')dnl

TEST_NC_PUT_VARS(text)
TEST_NC_PUT_VARS(uchar)
TEST_NC_PUT_VARS(schar)
TEST_NC_PUT_VARS(short)
TEST_NC_PUT_VARS(int)
TEST_NC_PUT_VARS(long)
TEST_NC_PUT_VARS(float)
TEST_NC_PUT_VARS(double)
TEST_NC_PUT_VARS(ushort)
TEST_NC_PUT_VARS(uint)
TEST_NC_PUT_VARS(longlong)
TEST_NC_PUT_VARS(ulonglong)


dnl TEST_NC_PUT_VARM(TYPE)
dnl
define(`TEST_NC_PUT_VARM',dnl
`dnl
int
TestFunc(varm)_$1(VarArgs)
{
    int i, k, d, err, nslabs, ncid, cdf_format, nok=0;
    int canConvert;     /* Both text or both numeric */
    int allInExtRange;  /* all values within external range? */
    IntType j, m, nels;
    IntType start[MAX_RANK], edge[MAX_RANK], index[MAX_RANK];
    IntType index2[MAX_RANK], mid[MAX_RANK], count[MAX_RANK];
    IntType sstride[MAX_RANK];
    PTRDType nstarts;   /* number of different starts */
    PTRDType stride[MAX_RANK], imap[MAX_RANK];
    $1 value[MAX_NELS];

    for(j = 0; j < MAX_RANK; j++) {
          start[j] = 0;
          edge[j] = 0;
          mid[j] = 0;
          index[j] = 0;
          index2[j] = 0;
          count[j] = 0;
          sstride[j] = 1;
          stride[j] = 1;
    }

    err = FileCreate(scratch, NC_CLOBBER);
    IF (err != NC_NOERR) {
        error("create: %s", APIFunc(strerror)(err));
        return nok;
    }

    err = APIFunc(inq_format)(ncid, &cdf_format);
    IF (err != NC_NOERR)
        error("inq_format: %s", APIFunc(strerror)(err));

    def_dims(ncid);
    DefVars(ncid, numVars);

    err = APIFunc(enddef)(ncid);
    IF (err != NC_NOERR)
        error("enddef: %s", APIFunc(strerror)(err));

    /* check if can detect a bad file ID */
    err = PutVarm($1)(BAD_ID, 0, NULL, NULL, NULL, NULL, NULL);
    IF (err != NC_EBADID)
        EXPECT_ERR(NC_EBADID, err)
    ELSE_NOK

    /* check if can detect a bad variable ID */
    err = PutVarm($1)(ncid, BAD_VARID, NULL, NULL, NULL, NULL, NULL);
    IF (err != NC_ENOTVAR)
        EXPECT_ERR(NC_ENOTVAR, err)
    ELSE_NOK

    for (i = 0; i < numVars; i++) {
        assert(var_rank[i] <= MAX_RANK);
        assert(var_nels[i] <= MAX_NELS);

        value[0] = 5; /* reset to a value within bounds */

        /* check if can detect a bad file ID */
        err = PutVarm($1)(BAD_ID, i, NULL, NULL, NULL, NULL, value);
        IF (err != NC_EBADID)
            EXPECT_ERR(NC_EBADID, err)
        ELSE_NOK

        canConvert = (var_type[i] == NC_CHAR) CheckText($1);

        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
            start[j] = 0;
            edge[j] = 1;
            stride[j] = 1;
            imap[j] = 1;
        }

ifdef(`PNETCDF',`dnl
        /* for non-scalar variables, argument start cannot be NULL */
        err = PutVarm($1)(ncid, i, NULL, NULL, NULL, NULL, value);
        if (!canConvert) {
            IF (err != NC_ECHAR) EXPECT_ERR(NC_ECHAR, err)
        }
        else if (var_rank[i] == 0) { /* scalar variable */
            IF (err != NC_NOERR) EXPECT_ERR(NC_NOERR, err)
        }
        else IF (err != NC_EINVALCOORDS) {
            EXPECT_ERR(NC_EINVALCOORDS, err)
        }
        ELSE_NOK

        /* for non-scalar variables, argument count cannot be NULL */
        err = PutVarm($1)(ncid, i, start, NULL, NULL, NULL, value);
        if (!canConvert) {
            IF (err != NC_ECHAR) EXPECT_ERR(NC_ECHAR, err)
        }
        else if (var_rank[i] == 0) { /* scalar variable */
            IF (err != NC_NOERR) EXPECT_ERR(NC_NOERR, err)
        }
        else IF (err != NC_EEDGE) {
            EXPECT_ERR(NC_EEDGE, err)
        }
        ELSE_NOK
')dnl

        /* first test when edge[*] > 0 */
        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
            if (var_dimid[i][j] == RECDIM) continue; /* skip record dim */
            start[j] = var_shape[i][j];   /* out of boundary check */
            err = PutVarm($1)(ncid, i, start, edge, stride, imap, value);
            if (!canConvert) {
                IF (err != NC_ECHAR)
                    EXPECT_ERR(NC_ECHAR, err)
                ELSE_NOK
                start[j] = 0;
                continue;
            }
            IF (err != NC_EINVALCOORDS)
                EXPECT_ERR(NC_EINVALCOORDS, err)
            ELSE_NOK
            start[j] = 0;
            edge[j] = var_shape[i][j] + 1;
            err = PutVarm($1)(ncid, i, start, edge, stride, imap, value);
            IF (err != NC_EEDGE)
                EXPECT_ERR(NC_EEDGE, err)
            ELSE_NOK
            edge[j] = 1;
            stride[j] = 0;
            err = PutVarm($1)(ncid, i, start, edge, stride, imap, value);
            IF (err != NC_ESTRIDE)
                EXPECT_ERR(NC_ESTRIDE, err)
            ELSE_NOK
            stride[j] = 1;
        }
        /* Check correct error returned when nothing to put, i.e. edge[*]==0 */
        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) edge[j] = 0;

        for (j = 0; j < var_rank[i]&& j < MAX_RANK; j++) {
            if (var_dimid[i][j] == RECDIM) continue; /* skip record dim */
            start[j] = var_shape[i][j];
            err = PutVarm($1)(ncid, i, start, edge, stride, imap, value);
            if (!canConvert) {
                IF (err != NC_ECHAR)
                    EXPECT_ERR(NC_ECHAR, err)
                ELSE_NOK
                start[j] = 0;
                continue;
            }
            IF (err != NC_NOERR) /* allowed when edge[j]==0 */
                EXPECT_ERR(NC_NOERR, err)
            ELSE_NOK
            start[j] = var_shape[i][j]+1; /* out of boundary check */
            err = PutVarm($1)(ncid, i, start, edge, stride, imap, value);
            IF (err != NC_EINVALCOORDS)
                EXPECT_ERR(NC_EINVALCOORDS, err)
            ELSE_NOK
            start[j] = 0;
        }
        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) edge[j] = 1;

        /* Choose a random point dividing each dim into 2 parts */
        /* Put 2^rank (nslabs) slabs so defined */
        nslabs = 1;
        for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
            mid[j] = roll( var_shape[i][j] );
            nslabs *= 2;
        }
        /* bits of k determine whether to put lower or upper part of dim */
        /* choose random stride from 1 to edge */
        for (k = 0; k < nslabs; k++) {
            nstarts = 1;
            for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
                if ((k >> j) & 1) {
                    start[j] = 0;
                    edge[j] = mid[j];
                } else {
                    start[j] = mid[j];
                    edge[j] = var_shape[i][j] - mid[j];
                }
                sstride[j] = edge[j] > 0 ? 1+roll(edge[j]) : 1;
                stride[j] = (PTRDType)sstride[j];
                nstarts *= stride[j];
            }
            for (m = 0; m < nstarts; m++) {
                err = toMixedBase(m, var_rank[i], sstride, index);
                IF (err != 0) error("error in toMixedBase");
                nels = 1;
                for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
                    count[j] = 1 + (edge[j] - index[j] - 1) / (IntType)stride[j];
                    nels *= count[j];
                    index[j] += start[j];
                }
                /* Random choice of forward or backward */
/* TODO
                if ( roll(2) ) {
                    for (j = 0; j < var_rank[i] && j < MAX_RANK; j++) {
                        index[j] += (count[j] - 1) * (IntType)stride[j];
                        stride[j] = -stride[j];
                    }
                }
*/
                if (var_rank[i] > 0) {
                    int jj = var_rank[i] - 1;
                    imap[jj] = 1;
                    for (; jj > 0; jj--)
                        imap[jj-1] = imap[jj] * (PTRDType)count[jj];
                }
                for (allInExtRange = 1, j = 0; j < nels; j++) {
                    err = toMixedBase(j, var_rank[i], count, index2);
                    IF (err != 0) error("error in toMixedBase");
                    for (d = 0; d < var_rank[i] && d < MAX_RANK; d++)
                        index2[d] = index[d] + index2[d] * (IntType)stride[d];
                    value[j] = hash_$1(cdf_format,var_type[i], var_rank[i],
                                       index2, NCT_ITYPE($1));
                    IfCheckTextChar($1, var_type[i])
                        allInExtRange &= inRange3(cdf_format, (double)value[j],
                                                  var_type[i], NCT_ITYPE($1));
                }
                err = PutVarm($1)(ncid,i,index,count,stride,imap,value);
                if (canConvert) {
                    if (allInExtRange) {
                        IF (err != NC_NOERR)
                            EXPECT_ERR(NC_NOERR, err)
                        ELSE_NOK
                    }
                    PNETCDF_CHECK_ERANGE($1)
                } else {
                    IF (err != NC_ECHAR)
                        EXPECT_ERR(NC_ECHAR, err)
                    ELSE_NOK
                }
            }
        }
    }

    err = APIFunc(close)(ncid);
    IF (err != NC_NOERR)
        error("close: %s", APIFunc(strerror)(err));

    nok += check_vars_$1(scratch, numVars);

    err = FileDelete(scratch, info);
    IF (err != NC_NOERR)
        error("delete file %s failed", scratch);
    return nok;
}
')dnl

TEST_NC_PUT_VARM(text)
TEST_NC_PUT_VARM(uchar)
TEST_NC_PUT_VARM(schar)
TEST_NC_PUT_VARM(short)
TEST_NC_PUT_VARM(int)
TEST_NC_PUT_VARM(long)
TEST_NC_PUT_VARM(float)
TEST_NC_PUT_VARM(double)
TEST_NC_PUT_VARM(ushort)
TEST_NC_PUT_VARM(uint)
TEST_NC_PUT_VARM(longlong)
TEST_NC_PUT_VARM(ulonglong)


int
TestFunc(att)_text(AttVarArgs)
{
    int i, j, err, ncid, nok=0;
    double dtmp;
    IntType k, ndx[1];
    text value[MAX_NELS];

    err = FileCreate(scratch, NC_NOCLOBBER);
    IF (err != NC_NOERR) {
        error("create: %s", APIFunc(strerror)(err));
        return nok;
    }
    def_dims(ncid);
    DefVars(ncid, numVars);

    /* check if can detect a bad file ID */
    err = PutAtt(text)(BAD_ID, 0, NULL, 0, NULL);
    IF (err != NC_EBADID)
        EXPECT_ERR(NC_EBADID, err)
    ELSE_NOK

    /* check if can detect a bad variable ID */
    err = PutAtt(text)(ncid, BAD_VARID, NULL, 0, NULL);
    IF (err != NC_ENOTVAR)
        EXPECT_ERR(NC_ENOTVAR, err)
    ELSE_NOK

    {
        const char *const tval = "value for bad name";
        const IntType tval_len = (IntType)strlen(tval);

        err = PutAtt(text)(ncid, 0, "", tval_len, tval);
        IF (err != NC_EBADNAME)
           EXPECT_ERR(NC_EBADNAME, err)
        ELSE_NOK
    }
    for (i = -1; i < numVars; i++) {
        for (j = 0; j < NATTS(i); j++) {
            if (ATT_TYPE(i,j) == NC_CHAR) {
                assert(ATT_LEN(i,j) <= MAX_NELS);

                err = PutAtt(text)(ncid, BAD_VARID, ATT_NAME(i,j), ATT_LEN(i,j), value);
                IF (err != NC_ENOTVAR)
                    EXPECT_ERR(NC_ENOTVAR, err)
                ELSE_NOK

                for (k = 0; k < ATT_LEN(i,j); k++) {
                    ndx[0] = k;
                    dtmp = hash(ATT_TYPE(i,j), -1, ndx);
                    value[k] = (text)dtmp;
                }
                err = PutAtt(text)(ncid, i, ATT_NAME(i,j), ATT_LEN(i,j), value);
                IF (err != NC_NOERR)
                    EXPECT_ERR(NC_NOERR, err)
                ELSE_NOK
            }
        }
    }

    nok += check_atts_text(ncid, numGatts, numVars);
    err = APIFunc(close)(ncid);
    IF (err != NC_NOERR)
        error("close: %s", APIFunc(strerror)(err));

    err = FileDelete(scratch, info);
    IF (err != NC_NOERR)
        error("delete file %s failed", scratch);
    return nok;
}


dnl TEST_NC_PUT_ATT(TYPE)         numeric only
dnl
define(`TEST_NC_PUT_ATT',dnl
`dnl
int
TestFunc(att)_$1(AttVarArgs)
{
    int i, j, err, ncid, cdf_format, nok=0;
    int allInExtRange;  /* all values within external range? */
    IntType k, ndx[1];
    $1 value[MAX_NELS];

    err = FileCreate(scratch, NC_NOCLOBBER);
    IF (err != NC_NOERR) {
        error("create: %s", APIFunc(strerror)(err));
        return nok;
    }

    err = APIFunc(inq_format)(ncid, &cdf_format);
    IF (err != NC_NOERR)
        error("inq_format: %s", APIFunc(strerror)(err));

    def_dims(ncid);
    DefVars(ncid, numVars);

    /* check if can detect a bad file ID */
    err = PutAtt($1)(BAD_ID, 0, NULL, 0, 0, NULL);
    IF (err != NC_EBADID)
        EXPECT_ERR(NC_EBADID, err)
    ELSE_NOK

    /* check if can detect a bad variable ID */
    err = PutAtt($1)(ncid, BAD_VARID, NULL, 0, 0, NULL);
    IF (err != NC_ENOTVAR)
        EXPECT_ERR(NC_ENOTVAR, err)
    ELSE_NOK

    for (i = -1; i < numVars; i++) {
        for (j = 0; j < NATTS(i); j++) {
            if (!(ATT_TYPE(i,j) == NC_CHAR)) {
                assert(ATT_LEN(i,j) <= MAX_NELS);

                err = PutAtt($1)(ncid, BAD_VARID, ATT_NAME(i,j), ATT_TYPE(i,j), ATT_LEN(i,j), value);
                IF (err != NC_ENOTVAR)
                    EXPECT_ERR(NC_ENOTVAR, err)
                ELSE_NOK

                /* check if can detect a bad name */
                err = PutAtt($1)(ncid, i, NULL, 0, 0, NULL);
                IF (err != NC_EBADNAME)
                    EXPECT_ERR(NC_EBADNAME, err)
                ELSE_NOK

                err = PutAtt($1)(ncid, i, ATT_NAME(i,j), BAD_TYPE, ATT_LEN(i,j), value);
                IF (err != NC_EBADTYPE)
                    EXPECT_ERR(NC_EBADTYPE, err)
                ELSE_NOK

                for (allInExtRange = 1, k = 0; k < ATT_LEN(i,j); k++) {
                    ndx[0] = k;
                    value[k] = hash_$1(cdf_format,ATT_TYPE(i,j), -1, ndx, NCT_ITYPE($1));
                    IfCheckTextChar($1, ATT_TYPE(i,j))
                        allInExtRange &= inRange3(cdf_format, (double)value[k], ATT_TYPE(i,j), NCT_ITYPE($1));
                }
                err = PutAtt($1)(ncid, i, ATT_NAME(i,j), ATT_TYPE(i,j), ATT_LEN(i,j), value);
                if (allInExtRange) {
                    IF (err != NC_NOERR)
                        EXPECT_ERR(NC_NOERR, err)
                    ELSE_NOK
                }
                PNETCDF_CHECK_ERANGE($1)
            }
        }
    }

    nok += check_atts_$1(ncid, numGatts, numVars);
    err = APIFunc(close)(ncid);
    IF (err != NC_NOERR)
        error("close: %s", APIFunc(strerror)(err));

    err = FileDelete(scratch, info);
    IF (err != NC_NOERR)
        error("delete file %s failed", scratch);
    return nok;
}
')dnl

TEST_NC_PUT_ATT(uchar)
TEST_NC_PUT_ATT(schar)
TEST_NC_PUT_ATT(short)
TEST_NC_PUT_ATT(int)
TEST_NC_PUT_ATT(long)
TEST_NC_PUT_ATT(float)
TEST_NC_PUT_ATT(double)
TEST_NC_PUT_ATT(ushort)
TEST_NC_PUT_ATT(uint)
TEST_NC_PUT_ATT(longlong)
TEST_NC_PUT_ATT(ulonglong)
