

#include <openssl/bio.h>
#include "testutil.h"

static const char *filename = NULL;


static int test_readbuffer_file_bio(int tstid)
{
    int ret = 0, len, partial;
    BIO *in = NULL, *in_bio = NULL, *readbuf_bio = NULL;
    char buf[255];
    char expected[4096];
    size_t readbytes = 0, bytes = 0, count = 0;

    
    if (!TEST_ptr(in = BIO_new_file(filename, "r"))
        || !TEST_int_eq(BIO_read_ex(in, expected, sizeof(expected),
                                    &readbytes), 1)
        || !TEST_int_lt(readbytes, sizeof(expected)))
        goto err;
    BIO_free(in);
    in = NULL;

    
    if (!TEST_ptr(readbuf_bio = BIO_new(BIO_f_readbuffer()))
        || !TEST_ptr(in_bio = BIO_new_file(filename, "r")))
        goto err;

    in_bio = BIO_push(readbuf_bio, in_bio);
    readbuf_bio = NULL;

    if (!TEST_int_eq(BIO_tell(in_bio), 0))
        goto err;

    if (tstid != 0) {
        partial = 4;
        while (!BIO_eof(in_bio)) {
            len = BIO_gets(in_bio, buf, sizeof(buf));
            if (len == 0) {
                if (!TEST_true(BIO_eof(in_bio)))
                    goto err;
            } else {
                if (!TEST_int_gt(len, 0)
                    || !TEST_int_le(len, (int)sizeof(buf) - 1))
                    goto err;
                if (!TEST_true(buf[len] == 0))
                    goto err;
                if (len > 1
                    && !BIO_eof(in_bio)
                    && len != ((int)sizeof(buf) - 1)
                    && !TEST_true(buf[len - 1] == '\n'))
                    goto err;
            }
            if (tstid == 1 && --partial == 0)
                break;
        }
    }
    if (!TEST_int_eq(BIO_seek(in_bio, 0), 1))
        goto err;

    len = 8; 
    while (!BIO_eof(in_bio)) {
        if (!TEST_int_eq(BIO_read_ex(in_bio, buf, len, &bytes), 1))
            break;
        if (!TEST_mem_eq(buf, bytes, expected + count, bytes))
            goto err;
        count += bytes;
        len = sizeof(buf); 
    }
    if (!TEST_int_eq(count, readbytes))
        goto err;
    ret = 1;
err:
    BIO_free(in);
    BIO_free_all(in_bio);
    BIO_free(readbuf_bio);
    return ret;
}

typedef enum OPTION_choice {
    OPT_ERR = -1,
    OPT_EOF = 0,
    OPT_TEST_ENUM
} OPTION_CHOICE;

const OPTIONS *test_get_options(void)
{
    static const OPTIONS test_options[] = {
        OPT_TEST_OPTIONS_WITH_EXTRA_USAGE("file\n"),
        { OPT_HELP_STR, 1, '-', "file\tFile to run tests on.\n" },
        { NULL }
    };
    return test_options;
}

int setup_tests(void)
{
    OPTION_CHOICE o;

    while ((o = opt_next()) != OPT_EOF) {
        switch (o) {
        case OPT_TEST_CASES:
            break;
        default:
            return 0;
        }
    }
    filename = test_get_argument(0);

    ADD_ALL_TESTS(test_readbuffer_file_bio, 3);
    return 1;
}
