/*
 * Copyright (C) by Argonne National Laboratory
 *     See COPYRIGHT in top-level directory
 */

#include "mpi.h"
#include "mpitestconf.h"
#include <stdio.h>

#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "mpitest.h"

/*
 * openerr - Test that errors on file open are handled correctly and that the
 * returned error message is accessible
 */
#define BUFLEN 10

int main(int argc, char *argv[])
{
    MPI_File fh;
    char emsg[MPI_MAX_ERROR_STRING];
    int emsglen, err, ec, errs = 0;
    int amode, rank;
    const char *name = 0;
    MPI_Status st;
    char outbuf[BUFLEN], inbuf[BUFLEN];

    MTest_Init(&argc, &argv);

    name = "not-a-file-to-use";
    /* Try to open a file that does/should not exist */
    /* Note that no error message should be printed by MPI_File_open,
     * even when there is an error */
    err = MPI_File_open(MPI_COMM_WORLD, name, MPI_MODE_RDONLY, MPI_INFO_NULL, &fh);
    if (err == MPI_SUCCESS) {
        errs++;
        printf("Did not return error when opening a file that does not exist\n");
        MPI_File_close(&fh);
        MPI_File_delete(name, MPI_INFO_NULL);
    } else {
        MPI_Error_class(err, &ec);
        MPI_Error_string(err, emsg, &emsglen);
        MTestPrintfMsg(2, "Error msg from open: %s\n", emsg);
        if (ec != MPI_ERR_NO_SUCH_FILE && ec != MPI_ERR_IO) {
            errs++;
            printf("Did not return class ERR_NO_SUCH_FILE or ERR_IO\n");
            printf("Returned class %d, message %s\n", ec, emsg);
        }
    }

    /* Now, create a file, write data into it; close, then reopen as
     * read only and try to write to it */

    amode = MPI_MODE_CREATE | MPI_MODE_WRONLY;
    name = "mpio-test-openerrs";

    err = MPI_File_open(MPI_COMM_WORLD, name, amode, MPI_INFO_NULL, &fh);
    if (err) {
        errs++;
        MTestPrintErrorMsg("Unable to open file for writing", err);
    } else {
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        memset(outbuf, 'A' + rank, BUFLEN);

        err = MPI_File_write_at(fh, rank * BUFLEN, outbuf, BUFLEN, MPI_BYTE, &st);
        if (err) {
            errs++;
            MTestPrintErrorMsg("Unable to write file", err);
        }
        MPI_File_close(&fh);
    }

    /* Now, open for read only, and delete on close */
    amode = MPI_MODE_RDONLY | MPI_MODE_DELETE_ON_CLOSE;

    err = MPI_File_open(MPI_COMM_WORLD, name, amode, MPI_INFO_NULL, &fh);
    if (err) {
        errs++;
        MTestPrintErrorMsg("Unable to reopen file for reading", err);
    } else {
        /* Try to read it */

        /* Clear buffer before reading into it */

        memset(inbuf, 0, BUFLEN);

        err = MPI_File_read_at(fh, rank * BUFLEN, inbuf, BUFLEN, MPI_BYTE, &st);
        if (err) {
            errs++;
            MTestPrintErrorMsg("Unable to read file", err);
        }

        /* Try to write it (should fail) */
        err = MPI_File_write_at(fh, rank * BUFLEN, outbuf, BUFLEN, MPI_BYTE, &st);
        if (err == MPI_SUCCESS) {
            errs++;
            printf("Write operation succeeded to read-only file\n");
        } else {
            /* Look at error class */
            MPI_Error_class(err, &ec);
            if (ec != MPI_ERR_READ_ONLY && ec != MPI_ERR_ACCESS) {
                errs++;
                printf("Unexpected error class %d when writing to read-only file\n", ec);
                MTestPrintErrorMsg("Error msg is: ", err);
            }
        }
        err = MPI_File_close(&fh);
        if (err) {
            errs++;
            MTestPrintErrorMsg("Failed to close", err);
        }

        /* No MPI_Barrier is required here */

        /*
         *  Test open without CREATE to see if DELETE_ON_CLOSE worked.
         *  This should fail if file was deleted correctly.
         */

        amode = MPI_MODE_RDONLY;
        err = MPI_File_open(MPI_COMM_WORLD, name, amode, MPI_INFO_NULL, &fh);
        if (err == MPI_SUCCESS) {
            errs++;
            printf("File was not deleted!\n");
            MPI_File_close(&fh);
        } else {
            MPI_Error_class(err, &ec);
            if (ec != MPI_ERR_NO_SUCH_FILE && ec != MPI_ERR_IO) {
                errs++;
                printf("Did not return class ERR_NO_SUCH_FILE or ERR_IO\n");
                printf("Returned class %d, message %s\n", ec, emsg);
            }
        }
    }
    /* */

    /* Find out how many errors we saw */
    MTest_Finalize(errs);

    return MTestReturnValue(errs);
}
