/* test_examplelib.c - Unit test untuk examplelib */
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "examplelib.h"

static int tests_run = 0;
static int tests_pass = 0;

#define ASSERT(cond, msg) \
    do { \
        tests_run++; \
        if (cond) { \
            tests_pass++; \
        } else { \
            printf("FAIL: %s (line %d)\n", msg, __LINE__); \
        } \
    } while (0)

static void test_version(void) {
    ASSERT(strcmp(exlib_version(), "1.0.0") == 0,
           "versi harus 1.0.0");
    ASSERT(strcmp(exlib_strerror(EXLIB_OK), "sukses") == 0,
           "strerror OK = 'sukses'");
    ASSERT(strcmp(exlib_strerror(EXLIB_ERR_NOT_FOUND),
                  "tidak ditemukan") == 0,
           "strerror NOT_FOUND sesuai");
}

static void test_mean(void) {
    double data[] = {1.0, 2.0, 3.0, 4.0, 5.0};
    double mean = 0.0;
    exlib_status s = exlib_mean(data, 5, &mean);
    ASSERT(s == EXLIB_OK, "mean harus sukses");
    ASSERT(fabs(mean - 3.0) < 1e-9, "mean = 3.0");

    s = exlib_mean(NULL, 5, &mean);
    ASSERT(s == EXLIB_ERR_NULL, "mean(NULL) = ERR_NULL");

    s = exlib_mean(data, 0, &mean);
    ASSERT(s == EXLIB_ERR_NULL, "mean n=0 = ERR_NULL");
}

static void test_stddev(void) {
    double data[] = {2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0};
    double sd = 0.0;
    exlib_status s = exlib_stddev(data, 8, &sd);
    ASSERT(s == EXLIB_OK, "stddev harus sukses");
    /* Standar deviasi populasi: sqrt(32/8) = 2.0 */
    ASSERT(fabs(sd - 2.0) < 1e-9, "stddev = 2.0");
}

static void test_reverse_bytes(void) {
    uint8_t data[] = {1, 2, 3, 4, 5};
    exlib_status s = exlib_reverse_bytes(data, 5);
    ASSERT(s == EXLIB_OK, "reverse sukses");
    ASSERT(data[0] == 5 && data[1] == 4 && data[2] == 3,
           "data setelah reverse = 5,4,3,2,1");
    ASSERT(data[3] == 2 && data[4] == 1, "data[3..4] = 2,1");

    s = exlib_reverse_bytes(NULL, 5);
    ASSERT(s == EXLIB_ERR_NULL, "reverse NULL = ERR_NULL");

    uint8_t single[] = {42};
    s = exlib_reverse_bytes(single, 1);
    ASSERT(s == EXLIB_OK, "reverse n=1 = OK");
    ASSERT(single[0] == 42, "single byte tidak berubah");
}

static void test_format_size(void) {
    char buf[32];

    exlib_status s = exlib_format_size(0, buf, sizeof(buf));
    ASSERT(s == EXLIB_OK, "format 0 = OK");
    ASSERT(strcmp(buf, "0.00 B") == 0, "0 bytes = '0.00 B'");

    s = exlib_format_size(1024ULL, buf, sizeof(buf));
    ASSERT(s == EXLIB_OK, "format 1024 = OK");
    ASSERT(strcmp(buf, "1.00 KB") == 0, "1024 = '1.00 KB'");

    s = exlib_format_size(1572864ULL, buf, sizeof(buf));
    ASSERT(s == EXLIB_OK, "format 1.5MB = OK");
    ASSERT(strcmp(buf, "1.50 MB") == 0, "1.5MB = '1.50 MB'");

    s = exlib_format_size(1073741824ULL, buf, sizeof(buf));
    ASSERT(s == EXLIB_OK, "format 1GB = OK");
    ASSERT(strcmp(buf, "1.00 GB") == 0, "1GB = '1.00 GB'");

    s = exlib_format_size(100, buf, 5);
    ASSERT(s == EXLIB_ERR_RANGE, "buffer kecil = ERR_RANGE");
}

static void test_contains(void) {
    exlib_status s = exlib_contains("hello world", "world");
    ASSERT(s == EXLIB_OK, "substring ditemukan");

    s = exlib_contains("hello world", "xyz");
    ASSERT(s == EXLIB_ERR_NOT_FOUND, "substring tidak ditemukan");

    s = exlib_contains("abc", "");
    ASSERT(s == EXLIB_OK, "needle kosong = OK");

    s = exlib_contains(NULL, "x");
    ASSERT(s == EXLIB_ERR_NULL, "NULL haystack = ERR_NULL");
}

int main(void) {
    test_version();
    test_mean();
    test_stddev();
    test_reverse_bytes();
    test_format_size();
    test_contains();

    printf("\n=== Hasil Test examplelib ===\n");
    printf("Total : %d\n", tests_run);
    printf("Lulus : %d\n", tests_pass);
    printf("Gagal : %d\n", tests_run - tests_pass);
    return (tests_run == tests_pass) ? 0 : 1;
}
