change: UI and migrate to gtest

This commit is contained in:
2026-07-27 05:27:32 +08:00
parent dd5508e571
commit a84e75ef47
56 changed files with 4484 additions and 4949 deletions
+72 -73
View File
@@ -28,6 +28,7 @@
// needed.
#include <assert.h>
#include <gtest/gtest.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -51,13 +52,13 @@ static void make_tmpdir(void)
#if defined(_WIN32)
char base[MAX_PATH];
const DWORD len = GetTempPathA(MAX_PATH, base);
assert(len > 0 && len < MAX_PATH);
EXPECT_TRUE(len > 0 && len < MAX_PATH);
snprintf(g_tmpdir, sizeof(g_tmpdir), "%soakengine_traverse_test_%lu", base,
(unsigned long)GetCurrentProcessId());
assert(_mkdir(g_tmpdir) == 0);
EXPECT_TRUE(_mkdir(g_tmpdir) == 0);
#else
strcpy(g_tmpdir, "/tmp/oakengine_traverse_test_XXXXXX");
assert(mkdtemp(g_tmpdir) != NULL);
EXPECT_TRUE(mkdtemp(g_tmpdir) != NULL);
#endif
}
@@ -67,46 +68,46 @@ static void test_null_robustness(OakEngineNode *solid)
{
double m[6];
assert(oakengine_traverse_generate_database(NULL, 0, 1, 1, 1) == NULL);
assert(oakengine_traverse_generate_table(NULL, 0, 1, 1, 1) == NULL);
EXPECT_TRUE(oakengine_traverse_generate_database(NULL, 0, 1, 1, 1) == NULL);
EXPECT_TRUE(oakengine_traverse_generate_table(NULL, 0, 1, 1, 1) == NULL);
// Zero denominators are invalid rationals.
assert(oakengine_traverse_generate_database(solid, 0, 0, 1, 1) == NULL);
assert(oakengine_traverse_generate_table(solid, 0, 1, 1, 0) == NULL);
EXPECT_TRUE(oakengine_traverse_generate_database(solid, 0, 0, 1, 1) == NULL);
EXPECT_TRUE(oakengine_traverse_generate_table(solid, 0, 1, 1, 0) == NULL);
oakengine_traverse_db_free(NULL); // no-op
assert(oakengine_traverse_db_input_count(NULL) == 0);
assert(oakengine_traverse_db_input_id(NULL, 0) == NULL);
assert(oakengine_traverse_db_row_count(NULL, 0) == 0);
assert(oakengine_traverse_row_type(NULL, 0, 0) == OAK_NODE_VALUE_NONE);
assert(oakengine_traverse_row_source(NULL, 0, 0) == NULL);
assert(oakengine_traverse_row_tag(NULL, 0, 0) != NULL); // never NULL
assert(oakengine_traverse_row_value_string(NULL, 0, 0) == NULL);
assert(oakengine_traverse_row_split_count(NULL, 0, 0) == 0);
assert(oakengine_traverse_row_split_string(NULL, 0, 0, 0) == NULL);
EXPECT_TRUE(oakengine_traverse_db_input_count(NULL) == 0);
EXPECT_TRUE(oakengine_traverse_db_input_id(NULL, 0) == NULL);
EXPECT_TRUE(oakengine_traverse_db_row_count(NULL, 0) == 0);
EXPECT_TRUE(oakengine_traverse_row_type(NULL, 0, 0) == OAK_NODE_VALUE_NONE);
EXPECT_TRUE(oakengine_traverse_row_source(NULL, 0, 0) == NULL);
EXPECT_TRUE(oakengine_traverse_row_tag(NULL, 0, 0) != NULL); // never NULL
EXPECT_TRUE(oakengine_traverse_row_value_string(NULL, 0, 0) == NULL);
EXPECT_TRUE(oakengine_traverse_row_split_count(NULL, 0, 0) == 0);
EXPECT_TRUE(oakengine_traverse_row_split_string(NULL, 0, 0, 0) == NULL);
assert(oakengine_traverse_table_element_index_for_hint(NULL, "x", -1,
EXPECT_TRUE(oakengine_traverse_table_element_index_for_hint(NULL, "x", -1,
NULL) == -1);
// generate_row: the C side can only exercise the error paths -- the
// real output is an olive::NodeValueRow (a C++ QHash typedef), which a
// pure C test cannot allocate. The filled-row path is covered by the
// application (the viewer display gizmo drag-start path).
assert(oakengine_traverse_generate_row(NULL, 0, 1, 1, 1, NULL, 0, 0,
EXPECT_TRUE(oakengine_traverse_generate_row(NULL, 0, 1, 1, 1, NULL, 0, 0,
(void *)1) == OAKENGINE_E_INVALID);
assert(oakengine_traverse_generate_row(solid, 0, 1, 1, 1, NULL, 0, 0,
EXPECT_TRUE(oakengine_traverse_generate_row(solid, 0, 1, 1, 1, NULL, 0, 0,
NULL) == OAKENGINE_E_INVALID);
assert(oakengine_traverse_transform(NULL, solid, 0, 1, 1, 1, NULL, m) ==
EXPECT_TRUE(oakengine_traverse_transform(NULL, solid, 0, 1, 1, 1, NULL, m) ==
OAKENGINE_E_INVALID);
assert(oakengine_traverse_transform(solid, NULL, 0, 1, 1, 1, NULL, m) ==
EXPECT_TRUE(oakengine_traverse_transform(solid, NULL, 0, 1, 1, 1, NULL, m) ==
OAKENGINE_E_INVALID);
assert(oakengine_traverse_transform(solid, solid, 0, 1, 1, 1, NULL,
EXPECT_TRUE(oakengine_traverse_transform(solid, solid, 0, 1, 1, 1, NULL,
NULL) == OAKENGINE_E_INVALID);
assert(oakengine_node_set_value_hint(NULL, "x", -1, OAK_NODE_VALUE_COLOR,
EXPECT_TRUE(oakengine_node_set_value_hint(NULL, "x", -1, OAK_NODE_VALUE_COLOR,
0, NULL) == OAKENGINE_E_INVALID);
assert(oakengine_node_set_value_hint(solid, NULL, -1,
EXPECT_TRUE(oakengine_node_set_value_hint(solid, NULL, -1,
OAK_NODE_VALUE_COLOR, 0,
NULL) == OAKENGINE_E_INVALID);
}
@@ -119,58 +120,58 @@ static void test_database(OakEngineNode *solid)
OakEngineTraverseDb *db =
oakengine_traverse_generate_database(solid, 0, 1, 1, 1);
assert(db != NULL);
EXPECT_TRUE(db != NULL);
// One entry per node input, in the node's input order (deterministic).
const int node_inputs = oakengine_node_input_count(solid);
assert(node_inputs >= 2);
assert(oakengine_traverse_db_input_count(db) == node_inputs);
EXPECT_TRUE(node_inputs >= 2);
EXPECT_TRUE(oakengine_traverse_db_input_count(db) == node_inputs);
for (int i = 0; i < node_inputs; i++) {
assert(oakengine_node_input_id(solid, i, buf, sizeof(buf)) > 0);
EXPECT_TRUE(oakengine_node_input_id(solid, i, buf, sizeof(buf)) > 0);
const char *id = oakengine_traverse_db_input_id(db, i);
assert(id != NULL);
assert(strcmp(id, buf) == 0);
EXPECT_TRUE(id != NULL);
EXPECT_TRUE(strcmp(id, buf) == 0);
// Every input of an unconnected Solid generator produces one row
// (its standard value).
const int rows = oakengine_traverse_db_row_count(db, i);
assert(rows >= 1);
EXPECT_TRUE(rows >= 1);
for (int r = 0; r < rows; r++) {
// Type is a valid facade value type for plain inputs
// (enabled_in is BOOL, color_in is COLOR).
const int type = oakengine_traverse_row_type(db, i, r);
assert(type > OAK_NODE_VALUE_NONE);
EXPECT_TRUE(type > OAK_NODE_VALUE_NONE);
// Source: the value's originating node, or NULL; the solid's
// standard values are sourced from the node itself.
OakEngineNode *src = oakengine_traverse_row_source(db, i, r);
assert(src == NULL || src == solid);
EXPECT_TRUE(src == NULL || src == solid);
// Tag may be empty but never NULL.
assert(oakengine_traverse_row_tag(db, i, r) != NULL);
EXPECT_TRUE(oakengine_traverse_row_tag(db, i, r) != NULL);
// Value string is non-empty for these value types.
const char *vs = oakengine_traverse_row_value_string(db, i, r);
assert(vs != NULL);
assert(vs[0] != '\0');
EXPECT_TRUE(vs != NULL);
EXPECT_TRUE(vs[0] != '\0');
// Split values: at least one track, each with a string.
const int splits = oakengine_traverse_row_split_count(db, i, r);
assert(splits >= 1);
EXPECT_TRUE(splits >= 1);
for (int s = 0; s < splits; s++) {
assert(oakengine_traverse_row_split_string(db, i, r, s) !=
EXPECT_TRUE(oakengine_traverse_row_split_string(db, i, r, s) !=
NULL);
}
assert(oakengine_traverse_row_split_string(db, i, r, splits) ==
EXPECT_TRUE(oakengine_traverse_row_split_string(db, i, r, splits) ==
NULL);
}
}
// Out-of-range accessors fail cleanly.
assert(oakengine_traverse_db_input_id(db, node_inputs) == NULL);
assert(oakengine_traverse_db_row_count(db, node_inputs) == 0);
assert(oakengine_traverse_row_type(db, node_inputs, 0) ==
EXPECT_TRUE(oakengine_traverse_db_input_id(db, node_inputs) == NULL);
EXPECT_TRUE(oakengine_traverse_db_row_count(db, node_inputs) == 0);
EXPECT_TRUE(oakengine_traverse_row_type(db, node_inputs, 0) ==
OAK_NODE_VALUE_NONE);
// A multi-entry database is not a generate_table result: the hint
// lookup rejects it.
assert(oakengine_traverse_table_element_index_for_hint(solid, "color_in",
EXPECT_TRUE(oakengine_traverse_table_element_index_for_hint(solid, "color_in",
-1, db) == -1);
oakengine_traverse_db_free(db);
@@ -182,35 +183,35 @@ static void test_table_and_hints(OakEngineNode *solid, OakEngineNode *lut)
{
OakEngineTraverseDb *db =
oakengine_traverse_generate_table(solid, 0, 1, 1, 1);
assert(db != NULL);
assert(oakengine_traverse_db_input_count(db) == 1);
EXPECT_TRUE(db != NULL);
EXPECT_TRUE(oakengine_traverse_db_input_count(db) == 1);
// The single output table is keyed by an empty input id.
const char *id = oakengine_traverse_db_input_id(db, 0);
assert(id != NULL);
assert(id[0] == '\0');
assert(oakengine_traverse_db_row_count(db, 0) >= 1);
EXPECT_TRUE(id != NULL);
EXPECT_TRUE(id[0] == '\0');
EXPECT_TRUE(oakengine_traverse_db_row_count(db, 0) >= 1);
// set_value_hint: unknown input ids and bogus types are rejected.
assert(oakengine_node_set_value_hint(solid, "not_an_input", -1,
EXPECT_TRUE(oakengine_node_set_value_hint(solid, "not_an_input", -1,
OAK_NODE_VALUE_COLOR, 0,
NULL) == OAKENGINE_E_NOT_FOUND);
assert(oakengine_node_set_value_hint(solid, "color_in", -1, 999, 0,
EXPECT_TRUE(oakengine_node_set_value_hint(solid, "color_in", -1, 999, 0,
NULL) == OAKENGINE_E_INVALID);
// The solid's output table holds texture rows. A hint preferring COLOR
// values (set on the lut's texture input) matches nothing -> -1.
assert(oakengine_node_set_value_hint(lut, "tex_in", -1,
EXPECT_TRUE(oakengine_node_set_value_hint(lut, "tex_in", -1,
OAK_NODE_VALUE_COLOR, -1,
NULL) == OAKENGINE_OK);
assert(oakengine_traverse_table_element_index_for_hint(lut, "tex_in", -1,
EXPECT_TRUE(oakengine_traverse_table_element_index_for_hint(lut, "tex_in", -1,
db) == -1);
// An untyped hint falls back to the input's declared type (k_texture
// for "tex_in"), which does have a row in the table.
assert(oakengine_node_set_value_hint(lut, "tex_in", -1,
EXPECT_TRUE(oakengine_node_set_value_hint(lut, "tex_in", -1,
OAK_NODE_VALUE_NONE, -1,
NULL) == OAKENGINE_OK);
assert(oakengine_traverse_table_element_index_for_hint(lut, "tex_in", -1,
EXPECT_TRUE(oakengine_traverse_table_element_index_for_hint(lut, "tex_in", -1,
db) >= 0);
oakengine_traverse_db_free(db);
@@ -223,46 +224,46 @@ static void test_transform(OakEngineNode *solid, OakEngineNode *lut)
double m[6] = { 0, 0, 0, 0, 0, 0 };
// No transform-generating nodes between start and end: identity matrix.
assert(oakengine_traverse_transform(solid, solid, 0, 1, 1, 1, NULL, m) ==
EXPECT_TRUE(oakengine_traverse_transform(solid, solid, 0, 1, 1, 1, NULL, m) ==
OAKENGINE_OK);
assert(m[0] == 1.0 && m[1] == 0.0 && m[2] == 0.0 && m[3] == 1.0);
assert(m[4] == 0.0 && m[5] == 0.0);
EXPECT_TRUE(m[0] == 1.0 && m[1] == 0.0 && m[2] == 0.0 && m[3] == 1.0);
EXPECT_TRUE(m[4] == 0.0 && m[5] == 0.0);
// Same through an edge, with explicit cache params.
oak_video_params vp;
memset(&vp, 0, sizeof(vp));
assert(oakengine_video_params_make(&vp, 1920, 1080, 1001, 30000, 0, 1, 1,
EXPECT_TRUE(oakengine_video_params_make(&vp, 1920, 1080, 1001, 30000, 0, 1, 1,
0, 0, 1) == OAKENGINE_OK);
memset(m, 0, sizeof(m));
assert(oakengine_traverse_transform(solid, lut, 0, 1, 1, 1, &vp, m) ==
EXPECT_TRUE(oakengine_traverse_transform(solid, lut, 0, 1, 1, 1, &vp, m) ==
OAKENGINE_OK);
assert(m[0] == 1.0 && m[1] == 0.0 && m[2] == 0.0 && m[3] == 1.0);
assert(m[4] == 0.0 && m[5] == 0.0);
EXPECT_TRUE(m[0] == 1.0 && m[1] == 0.0 && m[2] == 0.0 && m[3] == 1.0);
EXPECT_TRUE(m[4] == 0.0 && m[5] == 0.0);
}
int main(void)
TEST(OakEngineTraverse, Main)
{
make_tmpdir();
// Sandbox the config/cache/data locations.
#if !defined(_WIN32)
assert(setenv("XDG_CONFIG_HOME", g_tmpdir, 1) == 0);
assert(setenv("XDG_CACHE_HOME", g_tmpdir, 1) == 0);
assert(setenv("XDG_DATA_HOME", g_tmpdir, 1) == 0);
EXPECT_TRUE(setenv("XDG_CONFIG_HOME", g_tmpdir, 1) == 0);
EXPECT_TRUE(setenv("XDG_CACHE_HOME", g_tmpdir, 1) == 0);
EXPECT_TRUE(setenv("XDG_DATA_HOME", g_tmpdir, 1) == 0);
#endif
assert(oakengine_init(OAKENGINE_INIT_HEADLESS) == OAKENGINE_OK);
EXPECT_TRUE(oakengine_init(OAKENGINE_INIT_HEADLESS) == OAKENGINE_OK);
OakEngineProject *project = oakengine_project_create();
assert(project != NULL);
assert(oakengine_project_new(project) == OAKENGINE_OK);
EXPECT_TRUE(project != NULL);
EXPECT_TRUE(oakengine_project_new(project) == OAKENGINE_OK);
OakEngineNode *solid = oakengine_project_add_node(
project, "org.olivevideoeditor.Olive.solidgenerator");
assert(solid != NULL);
EXPECT_TRUE(solid != NULL);
OakEngineNode *lut = oakengine_project_add_node(
project, "org.olivevideoeditor.Olive.ociolut");
assert(lut != NULL);
EXPECT_TRUE(lut != NULL);
test_null_robustness(solid);
test_database(solid);
@@ -270,8 +271,6 @@ int main(void)
test_transform(solid, lut);
oakengine_project_free(project);
assert(oakengine_shutdown() == OAKENGINE_OK);
EXPECT_TRUE(oakengine_shutdown() == OAKENGINE_OK);
printf("oakengine_traverse_test: all assertions passed\n");
return 0;
}