56230dd340
- util/ref.c: refUnlock's assert(count >= 0) on an unsigned count was tautological, so a double-unlock silently underflowed to UINT32_MAX instead of asserting. Now asserts count > 0 before decrementing. - duskpsp/time/timepsp.c: timeGetRealTimeZonePSP returned hours while every other platform (and timeepoch.c's math) expects seconds. - thread.c: threadHandler reset threadId outside the mutex, after signaling STOPPED, letting a caller's immediate threadStart() race threadStartRequest()'s "thread id not 0" assert. threadId is now reset inside the same locked section. - tools/color.py: whole-number CSV channels (0, 1) produced invalid C float literals (0f, 1f) for the generated COLOR_*_3F/_4F macros. Route through float() so they always stringify with a decimal point. Also adds .claude/code-check.md: a full review pass over every subsystem in src/dusk/, with the above (plus several other findings not yet acted on) written up in detail. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
123 lines
3.9 KiB
C
123 lines
3.9 KiB
C
/**
|
|
* Copyright (c) 2026 Dominic Masters
|
|
*
|
|
* This software is released under the MIT License.
|
|
* https://opensource.org/licenses/MIT
|
|
*/
|
|
|
|
#include "dusktest.h"
|
|
#include "display/color.h"
|
|
|
|
static void test_color3f_create(void **state) {
|
|
color3f_t color = color3f(0.1f, 0.2f, 0.3f);
|
|
assert_float_equal(color.r, 0.1f, 0.0001f);
|
|
assert_float_equal(color.g, 0.2f, 0.0001f);
|
|
assert_float_equal(color.b, 0.3f, 0.0001f);
|
|
}
|
|
|
|
static void test_color4f_create(void **state) {
|
|
color4f_t color = color4f(0.1f, 0.2f, 0.3f, 0.4f);
|
|
assert_float_equal(color.r, 0.1f, 0.0001f);
|
|
assert_float_equal(color.g, 0.2f, 0.0001f);
|
|
assert_float_equal(color.b, 0.3f, 0.0001f);
|
|
assert_float_equal(color.a, 0.4f, 0.0001f);
|
|
}
|
|
|
|
static void test_color3b_create(void **state) {
|
|
color3b_t color = color3b(10, 20, 30);
|
|
assert_int_equal(color.r, 10);
|
|
assert_int_equal(color.g, 20);
|
|
assert_int_equal(color.b, 30);
|
|
}
|
|
|
|
static void test_color4b_create(void **state) {
|
|
|
|
color4b_t color = color4b(10, 20, 30, 40);
|
|
assert_int_equal(color.r, 10);
|
|
assert_int_equal(color.g, 20);
|
|
assert_int_equal(color.b, 30);
|
|
assert_int_equal(color.a, 40);
|
|
}
|
|
|
|
static void test_color_create(void **state) {
|
|
|
|
color_t color = color(10, 20, 30, 40);
|
|
assert_int_equal(color.r, 10);
|
|
assert_int_equal(color.g, 20);
|
|
assert_int_equal(color.b, 30);
|
|
assert_int_equal(color.a, 40);
|
|
}
|
|
|
|
static void test_colorHex_create(void **state) {
|
|
|
|
color_t color = colorHex(0x11223344);
|
|
assert_int_equal(color.r, 0x11);
|
|
assert_int_equal(color.g, 0x22);
|
|
assert_int_equal(color.b, 0x33);
|
|
assert_int_equal(color.a, 0x44);
|
|
|
|
color = colorHex(0xFF00FF00);
|
|
assert_int_equal(color.r, 0xFF);
|
|
assert_int_equal(color.g, 0x00);
|
|
assert_int_equal(color.b, 0xFF);
|
|
assert_int_equal(color.a, 0x00);
|
|
|
|
color_t comp = color(255, 0, 255, 0);
|
|
assert_int_equal(color.r, comp.r);
|
|
assert_int_equal(color.g, comp.g);
|
|
assert_int_equal(color.b, comp.b);
|
|
assert_int_equal(color.a, comp.a);
|
|
|
|
color = colorHex(0xFFFFFFFF);
|
|
assert_int_equal(color.r, COLOR_WHITE.r);
|
|
assert_int_equal(color.g, COLOR_WHITE.g);
|
|
assert_int_equal(color.b, COLOR_WHITE.b);
|
|
assert_int_equal(color.a, COLOR_WHITE.a);
|
|
}
|
|
|
|
// Exercises the color.csv-generated macros directly (COLOR_<NAME>_3F/_4F
|
|
// in particular) -- whole-number CSV channels like black/white's 0/1 once
|
|
// produced invalid C float literals ("0f"/"1f") in these, so referencing
|
|
// them here means a regression fails to compile instead of staying dead
|
|
// code no one notices.
|
|
static void test_generatedColor_wholeNumberChannels(void **state) {
|
|
color3f_t black3f = COLOR_BLACK_3F;
|
|
assert_float_equal(black3f.r, 0.0f, 0.0001f);
|
|
assert_float_equal(black3f.g, 0.0f, 0.0001f);
|
|
assert_float_equal(black3f.b, 0.0f, 0.0001f);
|
|
|
|
color4f_t white4f = COLOR_WHITE_4F;
|
|
assert_float_equal(white4f.r, 1.0f, 0.0001f);
|
|
assert_float_equal(white4f.g, 1.0f, 0.0001f);
|
|
assert_float_equal(white4f.b, 1.0f, 0.0001f);
|
|
assert_float_equal(white4f.a, 1.0f, 0.0001f);
|
|
|
|
color3b_t red3b = COLOR_RED_3B;
|
|
assert_int_equal(red3b.r, 255);
|
|
assert_int_equal(red3b.g, 0);
|
|
assert_int_equal(red3b.b, 0);
|
|
}
|
|
|
|
// A fractional channel (gray = 0.5) should generate the same way whole
|
|
// numbers do -- confirms the float()-based fix didn't just special-case 0/1.
|
|
static void test_generatedColor_fractionalChannel(void **state) {
|
|
color3f_t gray3f = COLOR_GRAY_3F;
|
|
assert_float_equal(gray3f.r, 0.5f, 0.0001f);
|
|
assert_float_equal(gray3f.g, 0.5f, 0.0001f);
|
|
assert_float_equal(gray3f.b, 0.5f, 0.0001f);
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
const struct CMUnitTest tests[] = {
|
|
cmocka_unit_test(test_color3f_create),
|
|
cmocka_unit_test(test_color4f_create),
|
|
cmocka_unit_test(test_color3b_create),
|
|
cmocka_unit_test(test_color4b_create),
|
|
cmocka_unit_test(test_color_create),
|
|
cmocka_unit_test(test_colorHex_create),
|
|
cmocka_unit_test(test_generatedColor_wholeNumberChannels),
|
|
cmocka_unit_test(test_generatedColor_fractionalChannel),
|
|
};
|
|
|
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
|
} |