trainlog/tui/tests/sync_generation_fixture.c

222 lines
8.3 KiB
C

/* Test-only producer fixture through the public desktop persistence API. */
#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "trainlog/database.h"
#include "trainlog/web_programs.h"
static const char PROGRAM_JSON[] =
"{\"format\":\"trainlog-program\",\"version\":1,\"program\":{"
"\"program_id\":\"pg_aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa\","
"\"title\":\"Generation program\",\"note\":null,\"state\":\"active\","
"\"start_date\":\"2026-09-21\",\"end_date\":null,\"sessions\":[{"
"\"program_session_id\":\"pgs_bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb\","
"\"title\":\"Session A\",\"session_type\":\"training\","
"\"planned_for\":null,\"note\":null,\"occurrences\":[{"
"\"entry_id\":\"pge_cccccccc-cccc-4ccc-8ccc-cccccccccccc\","
"\"exercise_id\":\"ex_dddddddd-dddd-4ddd-8ddd-dddddddddddd\","
"\"equipment_id\":null,\"load_mode\":\"external\",\"rest_seconds\":90,"
"\"target_sets\":3,\"target_reps\":8,\"target_duration_seconds\":null,"
"\"target_weight_kg\":40.0,\"notes\":null}]}]}}";
static int create_program(TrainlogDatabase *database) {
char *response = NULL;
size_t response_size = 0U;
TrainlogStatus status;
status = trainlog_database_insert_exercise_profiled(database,
"ex_dddddddd-dddd-4ddd-8ddd-dddddddddddd",
"Program exercise fixture",
"program exercise fixture",
TRAINLOG_TRACKING_REPS,
TRAINLOG_RECORDING_SETS,
0U);
if (status != TRAINLOG_STATUS_OK) {
return 3;
}
status = trainlog_web_programs_import_json(
database, PROGRAM_JSON, strlen(PROGRAM_JSON), true, &response, &response_size);
free(response);
response = NULL;
if (status != TRAINLOG_STATUS_OK ||
trainlog_web_programs_detail_json(
database, "pg_aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", &response, &response_size) !=
TRAINLOG_STATUS_OK) {
free(response);
return 4;
}
(void)printf("PROGRAM_CREATE=%s\n", response);
free(response);
return 0;
}
static int
delete_program(TrainlogDatabase *database, const char *expected_revision, const char *request_id) {
char *response = NULL;
size_t response_size = 0U;
TrainlogStatus status =
trainlog_web_programs_delete_json(database,
"pg_aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
expected_revision,
request_id,
&response,
&response_size);
if (status != TRAINLOG_STATUS_OK) {
free(response);
return 5;
}
(void)printf("PROGRAM_DELETE=%s\n", response);
free(response);
return 0;
}
static int create_session_fixture(TrainlogDatabase *database) {
TrainlogSetInput set = {.reps = 9, .has_weight = true, .weight_kg = 32.5};
TrainlogSessionExerciseInput exercise;
TrainlogSessionInput session;
if (trainlog_database_insert_exercise_profiled(database,
"ex_77777777-7777-4777-8777-777777777777",
"Desktop generation fixture",
"desktop generation fixture",
TRAINLOG_TRACKING_REPS,
TRAINLOG_RECORDING_SETS,
0U) != TRAINLOG_STATUS_OK) {
return 3;
}
(void)memset(&exercise, 0, sizeof(exercise));
(void)snprintf(exercise.entry_id,
sizeof(exercise.entry_id),
"%s",
"sxe_88888888-8888-4888-8888-888888888888");
(void)snprintf(exercise.exercise_id,
sizeof(exercise.exercise_id),
"%s",
"ex_77777777-7777-4777-8777-777777777777");
exercise.recording_mode = TRAINLOG_RECORDING_SETS;
exercise.tracking_mode = TRAINLOG_TRACKING_REPS;
exercise.sets = &set;
exercise.set_count = 1U;
(void)memset(&session, 0, sizeof(session));
(void)snprintf(session.session_id,
sizeof(session.session_id),
"%s",
"se_99999999-9999-4999-8999-999999999999");
(void)snprintf(
session.started_at, sizeof(session.started_at), "%s", "2026-09-17T10:00:00+02:00");
(void)snprintf(session.ended_at, sizeof(session.ended_at), "%s", "2026-09-17T10:30:00+02:00");
session.exercises = &exercise;
session.exercise_count = 1U;
if (trainlog_database_insert_session(database, &session) != TRAINLOG_STATUS_OK) {
return 4;
}
(void)puts("SYNC_GENERATION_FIXTURE=PASS");
return 0;
}
static int
check_integrity(sqlite3 *connection, bool *output_integrity_ok, bool *output_foreign_keys_ok) {
sqlite3_stmt *statement = NULL;
const unsigned char *integrity_result;
int rc;
*output_integrity_ok = false;
*output_foreign_keys_ok = false;
rc = sqlite3_prepare_v2(connection, "PRAGMA integrity_check;", -1, &statement, NULL);
if (rc != SQLITE_OK) {
return 1;
}
rc = sqlite3_step(statement);
integrity_result = rc == SQLITE_ROW ? sqlite3_column_text(statement, 0) : NULL;
*output_integrity_ok =
integrity_result != NULL && strcmp((const char *)integrity_result, "ok") == 0;
if (sqlite3_finalize(statement) != SQLITE_OK || !*output_integrity_ok) {
return 1;
}
rc = sqlite3_prepare_v2(connection, "PRAGMA foreign_key_check;", -1, &statement, NULL);
if (rc != SQLITE_OK) {
return 1;
}
rc = sqlite3_step(statement);
*output_foreign_keys_ok = rc == SQLITE_DONE;
if (sqlite3_finalize(statement) != SQLITE_OK || !*output_foreign_keys_ok) {
return 1;
}
return 0;
}
static int migrate_only(const char *path) {
TrainlogDatabase *database = NULL;
char diagnostic[256];
sqlite3 *inspection = NULL;
bool integrity_ok;
bool foreign_key_check_ok;
int foreign_keys_enabled;
int schema_version;
int result = 2;
if (trainlog_database_open_with_diagnostic(path, &database, diagnostic, sizeof(diagnostic)) !=
TRAINLOG_STATUS_OK) {
return result;
}
if (trainlog_database_schema_version(database, &schema_version) != TRAINLOG_STATUS_OK ||
trainlog_database_foreign_keys_enabled(database, &foreign_keys_enabled) !=
TRAINLOG_STATUS_OK) {
goto cleanup;
}
trainlog_database_close(database);
database = NULL;
if (sqlite3_open_v2(path, &inspection, SQLITE_OPEN_READONLY | SQLITE_OPEN_FULLMUTEX, NULL) !=
SQLITE_OK) {
goto cleanup;
}
if (check_integrity(inspection, &integrity_ok, &foreign_key_check_ok) != 0) {
goto cleanup;
}
(void)printf(
"MIGRATE_ONLY schema_version=%d integrity=%s foreign_keys=%s foreign_key_check=%s\n",
schema_version,
integrity_ok ? "ok" : "failed",
foreign_keys_enabled != 0 ? "enabled" : "disabled",
foreign_key_check_ok ? "ok" : "failed");
result = 0;
cleanup:
if (inspection != NULL) {
(void)sqlite3_close(inspection);
}
if (database != NULL) {
trainlog_database_close(database);
}
return result;
}
int main(int argc, char **argv) {
TrainlogDatabase *database = NULL;
int result;
if (argc == 3 && strcmp(argv[2], "migrate-only") == 0) {
return migrate_only(argv[1]);
}
if ((argc != 2 && argc != 3 && argc != 5) ||
trainlog_database_open(argv[1], &database) != TRAINLOG_STATUS_OK) {
return 2;
}
if (argc == 2) {
result = create_session_fixture(database);
} else if (argc == 3 && strcmp(argv[2], "program-create") == 0) {
result = create_program(database);
} else if (argc == 5 && strcmp(argv[2], "program-delete") == 0) {
result = delete_program(database, argv[3], argv[4]);
} else {
result = 2;
}
trainlog_database_close(database);
return result;
}