
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <errno.h>

#include "libgenudfimage.h"
#include "udffs.h"
#include "udferr.h"

static images_context *context = NULL;

static int main_ret = 0;
static int test_count = 0;
static int test_pass = 0;

#define EXPECT_EQ_BASE(equality, expect, actual, format) \
    do { \
        test_count++; \
        if (equality) { \
            test_pass++; \
        } else { \
            main_ret = 1; \
            udf_fprintf(stdout, "%s:%d: expect: "format", actual: "format"\n", __FILE__, __LINE__, expect, actual); \
        } \
    } while (0)

#define EXPECT_EQ_INT(expect, actual) EXPECT_EQ_BASE(expect == actual, expect, actual, "%d")
#define EXPECT_NE_INT(expect, actual) EXPECT_EQ_BASE(expect != actual, expect, actual, "%d")

static void test_invalid_opt()
{
    printf("------->test %s\n", __FUNCTION__);

    genudfimage_options opt;

    strcpy(opt.label, "test");
    strcpy(opt.version, "2.01");
    opt.blocksize = 2048;
    EXPECT_EQ_INT(-1, genudfimage_open("/tmp/test.udf", &opt));
    EXPECT_EQ_INT(errno, GENUDFIMAGE_INVALID_VAL);

    strcpy(opt.version, "1.02");
    opt.blocksize = 512;
    EXPECT_EQ_INT(-1, genudfimage_open("/tmp/test.udf", &opt));
    EXPECT_EQ_INT(errno, GENUDFIMAGE_INVALID_VAL);
    remove("/tmp/test.udf");
}

static void test_open_close()
{
    printf("------->test %s\n", __FUNCTION__);

    genudfimage_options opt;
    int fd;

    strcpy(opt.label, "test");
    strcpy(opt.version, "1.02");
    opt.blocksize = 2048;

    fd = genudfimage_open("/tmp/open_close.udf", &opt);
    EXPECT_NE_INT(-1, fd);
    EXPECT_NE_INT(-1, genudfimage_close(fd));
    remove("/tmp/open_close.udf");
}


static void test_mul_open_close()
{
    printf("------->test %s\n", __FUNCTION__);

    genudfimage_options opt;
    int fd;

    strcpy(opt.label, "test2");
    strcpy(opt.version, "1.02");
    opt.blocksize = 2048;

    fd = genudfimage_multisession_open("/tmp/mul_open_close.udf", &opt, 0, 2624, "/dev/sr0");

    EXPECT_NE_INT(-1, fd);
    EXPECT_NE_INT(-1, genudfimage_close(fd));
    remove("/tmp/mul_open_close.udf");
}

static void test_import_file()
{
    printf("------->test %s\n", __FUNCTION__);

    genudfimage_options opt;
    int fd;

    strcpy(opt.label, "test2");
    strcpy(opt.version, "1.02");
    opt.blocksize = 2048;

    fd = genudfimage_open("/tmp/open_close.udf", &opt);
    EXPECT_EQ_INT(GENUDFIMAGE_OK, genudfimage_import(fd, "/tmp/a"));
    EXPECT_EQ_INT(1, context->img_array[0]->cur_file_count);
    EXPECT_EQ_INT(0, strcmp("/tmp/a", context->img_array[0]->inner_files[0].file_name));

    EXPECT_EQ_INT(GENUDFIMAGE_EXPECT_UNIQ_FILE, genudfimage_import(fd, "/tmp/a"));
    EXPECT_EQ_INT(1, context->img_array[0]->cur_file_count);
    EXPECT_EQ_INT(0, strcmp("/tmp/a", context->img_array[0]->inner_files[0].file_name));

    EXPECT_EQ_INT(GENUDFIMAGE_OK, genudfimage_import(fd, "/tmp/b"));
    EXPECT_EQ_INT(2, context->img_array[0]->cur_file_count);
    EXPECT_EQ_INT(1, strcmp("/tmp/b", context->img_array[0]->inner_files[0].file_name));

    EXPECT_NE_INT(-1, fd);
    EXPECT_NE_INT(-1, genudfimage_close(fd));
    remove("/tmp/open_close.udf");
}

static void test_import_mul()
{
    printf("------->test %s\n", __FUNCTION__);

    genudfimage_options opt;
    int fd;

    strcpy(opt.label, "test2");
    strcpy(opt.version, "1.02");
    opt.blocksize = 2048;

    fd = genudfimage_open("/tmp/open_close.udf", &opt);
    EXPECT_EQ_INT(GENUDFIMAGE_INVALID_VAL, genudfimage_multisession_import(fd, "/tmp/a", NULL));

    EXPECT_NE_INT(-1, fd);
    EXPECT_NE_INT(-1, genudfimage_close(fd));
    remove("/tmp/open_close.udf");

}

static void do_test_generate()
{
    test_invalid_opt();
    test_open_close();
    test_mul_open_close();
    test_import_file();
    test_import_mul();
}

static void test_total_size()
{
    printf("------->test %s\n", __FUNCTION__);

    udf_image *img = NULL;
    uint64_t size = 0;
    uint64_t count = 0;
    genudfimage_options opt;
    int fd;

    strcpy(opt.label, "test2");
    strcpy(opt.version, "1.02");
    opt.blocksize = 2048;

    fd = genudfimage_open("/tmp/total_size.udf", &opt);
    EXPECT_NE_INT(-1, fd);
    img = context->img_array[0];
    // test
    size = img->total_size(img, &count);
    EXPECT_EQ_INT(0, size);
    EXPECT_EQ_INT(0, count);
    size = 0;
    count = 0;

    // not exists file
    EXPECT_EQ_INT(GENUDFIMAGE_OK, genudfimage_import(fd, "/tmp/not_exists"));
    size = img->total_size(img, &count);
    EXPECT_EQ_INT(0, size);
    EXPECT_EQ_INT(0, count);
    size = 0;
    count = 0;

    // empty dir (TODO: mkdir to /tmp)
    EXPECT_EQ_INT(GENUDFIMAGE_OK, genudfimage_import(fd, "/home/zhangs/test/empty"));
    size = img->total_size(img, &count);
    EXPECT_EQ_INT(4096, size);
    EXPECT_EQ_INT(1, count);
    size = 0;
    count = 0;

    // 10000 + 1
    EXPECT_EQ_INT(GENUDFIMAGE_OK, genudfimage_import(fd, "/home/zhangs/test/10000"));
    size = img->total_size(img, &count);
    EXPECT_EQ_INT(10002, count);

    EXPECT_NE_INT(-1, genudfimage_close(fd));
    remove("/tmp/total_size.udf");
}

static void test_make_empty()
{
    printf("------->test %s\n", __FUNCTION__);

    genudfimage_options opt;
    int fd;

    strcpy(opt.label, "test2");
    strcpy(opt.version, "1.02");
    opt.blocksize = 2048;

    fd = genudfimage_open("/tmp/make_empty.udf", &opt);
    EXPECT_NE_INT(-1, fd);
    EXPECT_EQ_INT(GENUDFIMAGE_EXPECT_FILE, genudfimage_make(fd));

    EXPECT_NE_INT(-1, genudfimage_close(fd));
    remove("/tmp/make_empty.udf");
}

static void test_make_file()
{
    printf("------->test %s\n", __FUNCTION__);

    remove("/tmp/make_file.udf");
    genudfimage_options opt;
    int fd;
    int v;

    strcpy(opt.label, "test2");
    strcpy(opt.version, "1.02");
    opt.blocksize = 2048;
    fd = genudfimage_open("/tmp/make_file.udf", &opt);
    EXPECT_NE_INT(-1, fd);

    v = genudfimage_import(fd, "/home/zhangs/Downloads/UDF-BUG");
    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
//    v = genudfimage_import(fd, "/home/zhangs/254fhdskfjjjdsghsdlfweuirhskdfhskfdhwsury529845shdfhsdkhfw84563grfweurweurfsjdfgkfgsdiruwerfsdjfsdkfgsdjgfsdjfffffffffffffffffffffffffgweiurrrfjsdgggggggggggggggggggggggggggggggvbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbn1.txt");
//    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
//    v = genudfimage_import(fd, "/home/zhangs/255fhdskfjjjdsghsdlfweuirhskdfhskfdhwsury529845shdfhsdkhfw84563grfweurweurfsjdfgkfgsdiruwerfsdjfsdkfgsdjgfsdjfffffffffffffffffffffffffgweiurrrfjsdgggggggggggggggggggggggggggggggvbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbn12.txt");
//    EXPECT_EQ_INT(GENUDFIMAGE_INVALID_NAME, v);
////    v = genudfimage_import(fd, "/home/zhangs/second");;
////    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
//    v = genudfimage_import(fd, "/home/zhangs/a.iso");
//    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
////    v = genudfimage_import(fd, "/home/zhangs/2.iso");;
////    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
//    v = genudfimage_import(fd, "/home/zhangs/source.iso");;
//    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
//    v = genudfimage_import(fd, "/home/zhangs/test/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcv.txt");;
//    v = genudfimage_import(fd, "/home/zhangs/test/1/baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcv.txt");;
//    v = genudfimage_import(fd, "/home/zhangs/test/1/caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcv.txt");;
//    v = genudfimage_import(fd, "/home/zhangs/test/1/daaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcv.txt");;
//    v = genudfimage_import(fd, "/home/zhangs/test/1/1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcv.txt");
//    v = genudfimage_import(fd, "/home/zhangs/test/1/2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcv.txt");
//    v = genudfimage_import(fd, "/home/zhangs/test/1/3aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcv.txt");
//    v = genudfimage_import(fd, "/home/zhangs/test/1/4aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcv.txt");
//    v = genudfimage_import(fd, "/home/zhangs/test/1/5aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcv.txt");
//    v = genudfimage_import(fd, "/home/zhangs/test/1/6aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcv.txt");
//    v = genudfimage_import(fd, "/home/zhangs/test/1/7aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcv.txt");
//    v = genudfimage_import(fd, "/home/zhangs/test/1/8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcv.txt");
//    v = genudfimage_import(fd, "/home/zhangs/test/1/8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcvaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbccccccccccccccccccdddddddddddddddddddddeeeeeeeeeeeeeeeeeefffffffffffffffffffgggggggggggggggggggggg.txt");
//    EXPECT_NE_INT(GENUDFIMAGE_OK, v);
//    v = genudfimage_import(fd, "/home/zhangs/test/0");
//    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);

    v = genudfimage_make(fd);
    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);

    EXPECT_NE_INT(-1, genudfimage_close(fd));
   // remove("/tmp/make_file.udf");
}

static void test_make_10000()
{
    printf("------->test %s\n", __FUNCTION__);

    remove("/tmp/make_10000.udf");
    genudfimage_options opt;
    int fd;
    int v;

    strcpy(opt.label, "test2");
    strcpy(opt.version, "1.02");
    opt.blocksize = 2048;
    fd = genudfimage_open("/tmp/make_10000.udf", &opt);
    EXPECT_NE_INT(-1, fd);
    v = genudfimage_import(fd, "/home/zhangs/test/10000");
    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
    v = genudfimage_make(fd);
    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);

    EXPECT_NE_INT(-1, genudfimage_close(fd));
    //remove("/tmp/make_10000.udf");
}

static void test_make_multi_file()
{
    printf("------->test %s\n", __FUNCTION__);

    remove("/tmp/make_mul.udf");
    genudfimage_options opt;
    int fd;
    int v;

    strcpy(opt.label, "test2");
    strcpy(opt.version, "1.02");
    opt.blocksize = 2048;
    fd = genudfimage_multisession_open("/tmp/make_mul.udf", &opt, 0, 2624, "/dev/sr0");
    EXPECT_NE_INT(-1, fd);

    v = genudfimage_multisession_import(fd, "/home/zhangs/1.iso", NULL);
    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
    v = genudfimage_multisession_import(fd, "/home/zhangs/test/1/a.txt", NULL);
    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
    v = genudfimage_multisession_import(fd, "/home/zhangs/Downloads/deb/20200413_214350.iso", NULL);
    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
#ifdef TEST_BIG_FILES
//    v = genudfimage_multisession_import(fd, "/home/zhangs/Downloads/deb/ubuntu-16.04.7-desktop-amd64.iso", NULL);
//    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
//    v = genudfimage_multisession_import(fd, "/home/zhangs/Downloads/deb/uniontechos-desktop-20-professional-1030-fix_mips64el.iso", NULL);
//    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
#endif
    v = genudfimage_multisession_import(fd, "/home/zhangs/test/1", NULL);
    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
    v = genudfimage_multisession_import(fd, "/home/zhangs/test/1/a", NULL);
    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
    v = genudfimage_multisession_import(fd, "/home/zhangs/test/10000", NULL);
    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
    v = genudfimage_multisession_import(fd, "/home/zhangs/test/0/NB.txt", NULL);
    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
    v = genudfimage_multisession_import(fd, "/home/zhangs/test/0/NB3.txt", NULL);
    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);
    v = genudfimage_make(fd);
    EXPECT_EQ_INT(GENUDFIMAGE_OK, v);

    EXPECT_NE_INT(-1, genudfimage_close(fd));
}

static void do_test_udffs()
{
    test_total_size();
    test_make_empty();
    test_make_file();
    test_make_10000();
    test_make_multi_file();
}

int main()
{
    context = context_get_default();
    do_test_generate();
    do_test_udffs();
    if (test_count > 0)
        printf("%d/%d (%3.2f%%) passed\n", test_pass, test_count, test_pass * 100.0 / test_count);
    return main_ret;
}
