#include "testing.h" #include static int child_count(rg_context *ctx, rg_node parent) { int n = 0; rg_node c; for (c = rg_node_first_child(ctx, parent); c != RG_NODE_NONE; c = rg_node_next_sibling(ctx, c)) n++; return n; } static void test_tree(rg_context *ctx) { rg_node root = rg_root(ctx); rg_node a = rg_node_create(ctx, RG_NODE_VBOX); rg_node b = rg_node_create(ctx, RG_NODE_LABEL); rg_node c = rg_node_create(ctx, RG_NODE_BUTTON); rg_node d = rg_node_create(ctx, RG_NODE_LABEL); CHECK(rg_node_valid(ctx, root)); CHECK(rg_node_type(ctx, root) == RG_NODE_ROOT); CHECK(rg_node_create(ctx, RG_NODE_ROOT) == RG_NODE_NONE); CHECK(rg_node_append(ctx, root, a) == RG_OK); CHECK(rg_node_append(ctx, a, b) == RG_OK); CHECK(rg_node_append(ctx, a, c) == RG_OK); CHECK(rg_node_insert_before(ctx, a, d, c) == RG_OK); CHECK(child_count(ctx, a) == 3); CHECK(rg_node_first_child(ctx, a) == b); CHECK(rg_node_next_sibling(ctx, b) == d); CHECK(rg_node_next_sibling(ctx, d) == c); CHECK(rg_node_next_sibling(ctx, c) == RG_NODE_NONE); CHECK(rg_node_parent(ctx, d) == a); CHECK(rg_node_append(ctx, a, b) == RG_OK); CHECK(rg_node_next_sibling(ctx, c) == b); CHECK(child_count(ctx, a) == 3); CHECK(rg_node_append(ctx, b, a) == RG_ERR_STATE); CHECK(rg_node_append(ctx, a, a) == RG_ERR_STATE); CHECK(rg_node_append(ctx, a, root) == RG_ERR_STATE); CHECK(rg_node_insert_before(ctx, root, b, c) == RG_ERR_STATE); CHECK(rg_node_detach(ctx, d) == RG_OK); CHECK(rg_node_parent(ctx, d) == RG_NODE_NONE); CHECK(child_count(ctx, a) == 2); rg_node_destroy(ctx, a); rg_node_destroy(ctx, d); } static void test_handles(rg_context *ctx) { rg_node root = rg_root(ctx); rg_node a = rg_node_create(ctx, RG_NODE_PANEL); rg_node b = rg_node_create(ctx, RG_NODE_LABEL); rg_node c = rg_node_create(ctx, RG_NODE_LABEL); rg_node fresh; CHECK(rg_node_append(ctx, root, a) == RG_OK); CHECK(rg_node_append(ctx, a, b) == RG_OK); CHECK(rg_node_append(ctx, b, c) == RG_OK); rg_node_destroy(ctx, a); CHECK(!rg_node_valid(ctx, a)); CHECK(!rg_node_valid(ctx, b)); CHECK(!rg_node_valid(ctx, c)); CHECK(rg_set_float(ctx, b, RG_PROP_GAP, 1.0f) == RG_ERR_HANDLE); CHECK(child_count(ctx, root) == 0); fresh = rg_node_create(ctx, RG_NODE_BOX); CHECK(fresh != a && fresh != b && fresh != c); CHECK(!rg_node_valid(ctx, a)); CHECK(rg_node_valid(ctx, fresh)); rg_node_destroy(ctx, root); CHECK(rg_node_valid(ctx, root)); rg_node_destroy(ctx, fresh); } static void test_props(rg_context *ctx) { rg_node hbox = rg_node_create(ctx, RG_NODE_HBOX); rg_node vbox = rg_node_create(ctx, RG_NODE_VBOX); rg_node btn = rg_node_create(ctx, RG_NODE_BUTTON); rg_node lbl = rg_node_create(ctx, RG_NODE_LABEL); rg_value v; char buf[16]; int i; for (i = 0; i < RG_PROP_COUNT; i++) { CHECK(rg_prop_name(i) != NULL); CHECK(rg_prop_find(rg_prop_name(i)) == i); CHECK(rg_prop_type(i) != RG_VAL_NONE); } CHECK(rg_prop_find("no_such_prop") == -1); CHECK(rg_type_find("Button") == RG_NODE_BUTTON); CHECK(rg_type_find("Nope") == -1); CHECK(rg_get(ctx, hbox, RG_PROP_DIRECTION, &v) == RG_OK && v.i == RG_DIR_ROW); CHECK(rg_get(ctx, vbox, RG_PROP_DIRECTION, &v) == RG_OK && v.i == RG_DIR_COLUMN); CHECK(rg_get(ctx, btn, RG_PROP_PADDING, &v) == RG_OK); CHECK(v.f[0] == 8.0f && v.f[1] == 16.0f && v.f[2] == 8.0f && v.f[3] == 16.0f); CHECK(rg_get(ctx, lbl, RG_PROP_OPACITY, &v) == RG_OK && v.f[0] == 1.0f); CHECK(rg_get(ctx, lbl, RG_PROP_TEXT, &v) == RG_OK && strcmp(v.s, "") == 0); CHECK(rg_set_int(ctx, vbox, RG_PROP_DIRECTION, RG_DIR_ROW) == RG_OK); CHECK(rg_get(ctx, vbox, RG_PROP_DIRECTION, &v) == RG_OK && v.i == RG_DIR_ROW); CHECK(rg_unset(ctx, vbox, RG_PROP_DIRECTION) == RG_OK); CHECK(rg_get(ctx, vbox, RG_PROP_DIRECTION, &v) == RG_OK && v.i == RG_DIR_COLUMN); CHECK(rg_unset(ctx, vbox, RG_PROP_DIRECTION) == RG_OK); CHECK(rg_set_color(ctx, btn, RG_PROP_BACKGROUND, 1, 0, 0, 1) == RG_OK); CHECK(rg_get(ctx, btn, RG_PROP_BACKGROUND, &v) == RG_OK && v.f[0] == 1.0f && v.f[1] == 0.0f); CHECK(rg_set_float(ctx, btn, RG_PROP_BACKGROUND, 1.0f) == RG_ERR_TYPE); CHECK(rg_set_int(ctx, btn, RG_PROP_GAP, 1) == RG_ERR_TYPE); CHECK(rg_set(ctx, btn, RG_PROP_GAP, NULL) == RG_ERR_TYPE); CHECK(rg_set_string(ctx, btn, RG_PROP_TEXT, NULL) == RG_ERR_TYPE); CHECK(rg_set_float(ctx, btn, 9999, 1.0f) == RG_ERR_PROP); CHECK(rg_get(ctx, btn, -1, &v) == RG_ERR_PROP); memset(&v, 0, sizeof v); v.type = RG_VAL_SIZE; v.i = 99; CHECK(rg_set(ctx, btn, RG_PROP_WIDTH, &v) == RG_ERR_TYPE); v.i = RG_SIZE_FIXED; v.f[0] = 200.0f; CHECK(rg_set(ctx, btn, RG_PROP_WIDTH, &v) == RG_OK); strcpy(buf, "Start"); CHECK(rg_set_string(ctx, lbl, RG_PROP_TEXT, buf) == RG_OK); strcpy(buf, "Other"); CHECK(rg_get(ctx, lbl, RG_PROP_TEXT, &v) == RG_OK && strcmp(v.s, "Start") == 0); CHECK(rg_set_string(ctx, lbl, RG_PROP_TEXT, v.s) == RG_OK); CHECK(rg_get(ctx, lbl, RG_PROP_TEXT, &v) == RG_OK && strcmp(v.s, "Start") == 0); CHECK(rg_set_string(ctx, lbl, RG_PROP_TEXT, "A much longer replacement string") == RG_OK); CHECK(rg_get(ctx, lbl, RG_PROP_TEXT, &v) == RG_OK && strcmp(v.s, "A much longer replacement string") == 0); for (i = 0; i < RG_PROP_COUNT; i++) { rg_value tmp; memset(&tmp, 0, sizeof tmp); tmp.type = rg_prop_type(i); tmp.s = tmp.type == RG_VAL_STRING ? "x" : NULL; if (tmp.type == RG_VAL_SIZE) tmp.i = RG_SIZE_FIT; CHECK(rg_set(ctx, btn, i, &tmp) == RG_OK); } rg_node_destroy(ctx, hbox); rg_node_destroy(ctx, vbox); rg_node_destroy(ctx, btn); rg_node_destroy(ctx, lbl); } int main(void) { testing_alloc ta = {0, 0}; rg_config cfg; rg_context *ctx; rg_config_init(&cfg); testing_use_counting_allocator(&cfg, &ta); cfg.log_level = RG_LOG_WARN; ctx = rg_create(&cfg); CHECK(ctx != NULL); if (!ctx) return 1; test_tree(ctx); test_handles(ctx); test_props(ctx); rg_destroy(ctx); CHECK(ta.live == 0); if (ta.live != 0) printf("leak: %zu bytes still live\n", ta.live); printf("nodes: %s, peak %zu bytes\n", g_failures ? "FAILED" : "ok", ta.peak); return g_failures ? 1 : 0; }