#include <TestConfig.h>
#include <TestFramework.h>

#include "htio2/Cast.h"
#include "htio2/StringUtil.h"

#include <limits.h>
#include <limits>

#include <sstream>

using namespace htio2;
using namespace std;

#define FROM_STRING_TEST(__type__, __value__) {\
        ostringstream tmp_input;\
        tmp_input << " \t" << (__value__) << "  ";\
        __type__ tmp_output = 0;\
        ok(from_string<__type__>(tmp_input.str(), tmp_output), ("cast \""+tmp_input.str()+"\"").c_str());\
        IS(tmp_output, __value__);\
    }\

#define FROM_STRING_TEST_EPSILON(__type__, __value__, __epsilon__) {\
        ostringstream tmp_input;\
        tmp_input << " \t " << (__value__) << "  ";\
        __type__ tmp_output = 0;\
        ok(from_string<__type__>(tmp_input.str(), tmp_output), ("cast \""+tmp_input.str()+"\"").c_str());\
        is_epsilon(tmp_output, __value__, EXPAND_AND_STRINGIFY(tmp_output) " ~~ " EXPAND_AND_STRINGIFY(__value__), __epsilon__);\
    }\

#define FROM_STRING_TEST_ENUM(__type__, __input_str__, __value__) {\
        __type__ tmp_output;\
        ok(from_string<__type__>(__input_str__, tmp_output), (string("cast \"")+__input_str__+"\"").c_str());\
        IS(tmp_output, __value__);\
    }\

void TestFramework::content()
{
    // integer types
    FROM_STRING_TEST(short, SHRT_MIN);
    FROM_STRING_TEST(short, SHRT_MAX);
    FROM_STRING_TEST(int, INT_MIN);
    FROM_STRING_TEST(int, INT_MAX);
    FROM_STRING_TEST(long, LONG_MIN);
    FROM_STRING_TEST(long, LONG_MAX);
    FROM_STRING_TEST(long long, LONG_LONG_MIN);
    FROM_STRING_TEST(long long, LONG_LONG_MAX);

    FROM_STRING_TEST(unsigned short, 0);
    FROM_STRING_TEST(unsigned short, USHRT_MAX);
    FROM_STRING_TEST(unsigned int, 0);
    FROM_STRING_TEST(unsigned int, UINT_MAX);
    FROM_STRING_TEST(unsigned long, 0);
    FROM_STRING_TEST(unsigned long, ULONG_MAX);
    FROM_STRING_TEST(unsigned long long, 0);
    FROM_STRING_TEST(unsigned long long, ULONG_LONG_MAX);

    // floating point types
    FROM_STRING_TEST_EPSILON(float, numeric_limits<float>::min(), 10000.0f);
    FROM_STRING_TEST_EPSILON(float, numeric_limits<float>::max(), 10000.0f);
    FROM_STRING_TEST_EPSILON(double, numeric_limits<double>::min(), 10000.0);
    FROM_STRING_TEST_EPSILON(double, numeric_limits<double>::max(), 10000.0);

    // enum types
    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "unknown", htio2::COMPRESS_UNKNOWN);
    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "plain", htio2::COMPRESS_PLAIN);
    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "xz", htio2::COMPRESS_LZMA);
    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "lzma", htio2::COMPRESS_LZMA);
    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "gz", htio2::COMPRESS_GZIP);
    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "gzip", htio2::COMPRESS_GZIP);
    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "bz2", htio2::COMPRESS_BZIP2);
    FROM_STRING_TEST_ENUM(htio2::CompressFormat, "bzip2", htio2::COMPRESS_BZIP2);

    FROM_STRING_TEST_ENUM(htio2::SeqFormat, "fastq", htio2::FORMAT_FASTQ);
    FROM_STRING_TEST_ENUM(htio2::SeqFormat, "fq", htio2::FORMAT_FASTQ);
    FROM_STRING_TEST_ENUM(htio2::SeqFormat, "fasta", htio2::FORMAT_FASTA);
    FROM_STRING_TEST_ENUM(htio2::SeqFormat, "fas", htio2::FORMAT_FASTA);
    FROM_STRING_TEST_ENUM(htio2::SeqFormat, "fa", htio2::FORMAT_FASTA);
    FROM_STRING_TEST_ENUM(htio2::SeqFormat, "fna", htio2::FORMAT_FASTA);
}
