Foundry/progress/tests/test_progress.c

273 lines
6.7 KiB
C

/* SPDX-License-Identifier: AGPL-3.0-or-later */
/* Copyright (C) 2026 David (Corey) Herrera */
#include "../../lib/test.h"
#include "../progress.h"
#include <unistd.h>
/* ============================================================= */
/* fp_new tests */
/* ============================================================= */
static void test_creates_progress_bar(void) {
fp_progress* p = fp_new(100, "Test");
ASSERT_NOT_NULL(p);
fp_free(p);
}
static void test_null_description_ok(void) {
fp_progress* p = fp_new(100, NULL);
ASSERT_NOT_NULL(p);
fp_free(p);
}
static void test_zero_total_ok(void) {
fp_progress* p = fp_new(0, "Empty");
ASSERT_NOT_NULL(p);
fp_free(p);
}
/* ============================================================= */
/* fp_total / fp_current tests */
/* ============================================================= */
static void test_total_returns_initial_value(void) {
fp_progress* p = fp_new(500, "Test");
ASSERT_INT_EQ(500, fp_total(p));
fp_free(p);
}
static void test_current_starts_at_zero(void) {
fp_progress* p = fp_new(100, "Test");
ASSERT_INT_EQ(0, fp_current(p));
fp_free(p);
}
static void test_percent_starts_at_zero(void) {
fp_progress* p = fp_new(100, "Test");
ASSERT_FLT_NEAR(0.0f, fp_percent(p), 0.01f);
fp_free(p);
}
/* ============================================================= */
/* fp_update tests */
/* ============================================================= */
static void test_update_increments_current(void) {
fp_progress* p = fp_new(100, "Test");
fp_disable(p);
fp_update(p, 10);
ASSERT_INT_EQ(10, fp_current(p));
fp_update(p, 5);
ASSERT_INT_EQ(15, fp_current(p));
fp_free(p);
}
static void test_update_clamps_to_total(void) {
fp_progress* p = fp_new(100, "Test");
fp_disable(p);
fp_update(p, 150);
ASSERT_INT_EQ(100, fp_current(p));
fp_free(p);
}
static void test_percent_updates_correctly(void) {
fp_progress* p = fp_new(100, "Test");
fp_disable(p);
fp_update(p, 50);
ASSERT_FLT_NEAR(50.0f, fp_percent(p), 0.01f);
fp_update(p, 50);
ASSERT_FLT_NEAR(100.0f, fp_percent(p), 0.01f);
fp_free(p);
}
/* ============================================================= */
/* fp_set tests */
/* ============================================================= */
static void test_set_absolute_position(void) {
fp_progress* p = fp_new(100, "Test");
fp_disable(p);
fp_set(p, 75);
ASSERT_INT_EQ(75, fp_current(p));
fp_free(p);
}
/* ============================================================= */
/* fp_rate / fp_eta tests */
/* ============================================================= */
static void test_elapsed_increases(void) {
fp_progress* p = fp_new(100, "Test");
fp_disable(p);
double t1 = fp_elapsed(p);
usleep(10000); /* 10ms */
double t2 = fp_elapsed(p);
ASSERT_DBL_GT(t2, t1);
fp_free(p);
}
static void test_rate_is_positive_after_update(void) {
fp_progress* p = fp_new(100, "Test");
fp_disable(p);
fp_update(p, 10);
usleep(10000); /* 10ms */
double rate = fp_rate(p);
ASSERT_DBL_GT(rate, 0.0);
fp_free(p);
}
static void test_eta_decreases_as_progress_increases(void) {
fp_progress* p = fp_new(100, "Test");
fp_disable(p);
fp_update(p, 10);
usleep(10000);
double eta1 = fp_eta(p);
fp_update(p, 40);
usleep(10000);
double eta2 = fp_eta(p);
ASSERT_DBL_LT(eta2, eta1);
fp_free(p);
}
/* ============================================================= */
/* fp_set_postfix tests */
/* ============================================================= */
static void test_postfix_does_not_crash(void) {
fp_progress* p = fp_new(100, "Test");
fp_disable(p);
fp_set_postfix(p, "loss=%.4f, lr=%.2e", 0.1234, 1e-5);
fp_update(p, 10);
ASSERT_TRUE(1);
fp_free(p);
}
/* ============================================================= */
/* fp_train_state tests */
/* ============================================================= */
static void test_log_step_does_not_crash(void) {
fp_train_state state = {
.epoch = 1,
.step = 100,
.loss = 0.5f,
.lr = 1e-4f,
.throughput = 1000.0f
};
fp_log_step(&state);
ASSERT_TRUE(1);
}
static void test_log_epoch_does_not_crash(void) {
fp_train_state state = {
.epoch = 5,
.step = 5000,
.loss = 0.1f,
.lr = 1e-5f,
.throughput = 1200.0f
};
fp_log_epoch(&state);
ASSERT_TRUE(1);
}
/* ============================================================= */
/* Edge cases */
/* ============================================================= */
static void test_null_progress_is_safe(void) {
fp_update(NULL, 10);
fp_set(NULL, 10);
fp_close(NULL);
fp_free(NULL);
ASSERT_INT_EQ(0, fp_total(NULL));
ASSERT_INT_EQ(0, fp_current(NULL));
ASSERT_DBL_EQ(0.0, fp_elapsed(NULL));
ASSERT_DBL_EQ(0.0, fp_rate(NULL));
ASSERT_DBL_EQ(0.0, fp_eta(NULL));
ASSERT_FLT_EQ(0.0f, fp_percent(NULL));
}
static void test_close_is_idempotent(void) {
fp_progress* p = fp_new(100, "Test");
fp_disable(p);
fp_close(p);
fp_close(p);
fp_close(p);
ASSERT_TRUE(1);
fp_free(p);
}
/* ============================================================= */
/* Main */
/* ============================================================= */
int main(void) {
printf("\n Running progress tests...\n\n");
/* fp_new tests */
RUN_TEST(creates_progress_bar);
RUN_TEST(null_description_ok);
RUN_TEST(zero_total_ok);
/* Accessor tests */
RUN_TEST(total_returns_initial_value);
RUN_TEST(current_starts_at_zero);
RUN_TEST(percent_starts_at_zero);
/* fp_update tests */
RUN_TEST(update_increments_current);
RUN_TEST(update_clamps_to_total);
RUN_TEST(percent_updates_correctly);
/* fp_set tests */
RUN_TEST(set_absolute_position);
/* Timing tests */
RUN_TEST(elapsed_increases);
RUN_TEST(rate_is_positive_after_update);
RUN_TEST(eta_decreases_as_progress_increases);
/* Postfix tests */
RUN_TEST(postfix_does_not_crash);
/* Training log tests */
RUN_TEST(log_step_does_not_crash);
RUN_TEST(log_epoch_does_not_crash);
/* Edge cases */
RUN_TEST(null_progress_is_safe);
RUN_TEST(close_is_idempotent);
TEST_REPORT();
return __ft_failed > 0 ? 1 : 0;
}