#include "amduat/enc/asl_tgk_exec_plan.h" #include #include #include #include #include enum { k_plan_header_size = 8, k_params_size = 65, k_operator_size = 129, k_input_offset = 97 }; static bool read_file(const char *path, uint8_t **out_bytes, size_t *out_len) { FILE *fp; long size; uint8_t *buffer; size_t read_len; if (path == NULL || out_bytes == NULL || out_len == NULL) { return false; } *out_bytes = NULL; *out_len = 0u; fp = fopen(path, "rb"); if (fp == NULL) { return false; } if (fseek(fp, 0, SEEK_END) != 0) { fclose(fp); return false; } size = ftell(fp); if (size < 0) { fclose(fp); return false; } if (fseek(fp, 0, SEEK_SET) != 0) { fclose(fp); return false; } buffer = (uint8_t *)malloc((size_t)size + 1u); if (buffer == NULL) { fclose(fp); return false; } read_len = fread(buffer, 1u, (size_t)size, fp); fclose(fp); if (read_len != (size_t)size) { free(buffer); return false; } buffer[size] = '\0'; *out_bytes = buffer; *out_len = (size_t)size; return true; } static bool build_fixture_path(char *out, size_t out_len) { const char *needle = "/tests/enc/"; const char *path = __FILE__; const char *pos = strstr(path, needle); size_t prefix_len; if (pos == NULL) { return false; } prefix_len = (size_t)(pos - path); if (prefix_len + strlen("/tests/fixtures/conformance/" "asl_tgk_exec_plan/artifacts/plan0.bin") + 1u > out_len) { return false; } memcpy(out, path, prefix_len); out[prefix_len] = '\0'; strcat(out, "/tests/fixtures/conformance/" "asl_tgk_exec_plan/artifacts/plan0.bin"); return true; } static void store_u32_le(uint8_t *out, uint32_t value) { out[0] = (uint8_t)(value & 0xffu); out[1] = (uint8_t)((value >> 8) & 0xffu); out[2] = (uint8_t)((value >> 16) & 0xffu); out[3] = (uint8_t)((value >> 24) & 0xffu); } static void fill_default_params(amduat_asl_tgk_exec_operator_params_t *params) { memset(params, 0, sizeof(*params)); params->tgk_traversal.direction = 1u; } static int test_round_trip(void) { amduat_asl_tgk_exec_operator_def_t operators[2]; amduat_asl_tgk_exec_plan_t plan; amduat_octets_t encoded; amduat_asl_tgk_exec_plan_t decoded; int exit_code = 1; memset(operators, 0, sizeof(operators)); fill_default_params(&operators[0].params); fill_default_params(&operators[1].params); operators[0].op_id = 1u; operators[0].op_type = AMDUAT_ASL_TGK_EXEC_OP_SEGMENT_SCAN; operators[0].flags = AMDUAT_ASL_TGK_EXEC_OP_FLAG_NONE; operators[0].snapshot.logseq_min = 0u; operators[0].snapshot.logseq_max = 10u; operators[0].input_count = 0u; operators[1].op_id = 2u; operators[1].op_type = AMDUAT_ASL_TGK_EXEC_OP_TGK_TRAVERSAL; operators[1].flags = AMDUAT_ASL_TGK_EXEC_OP_FLAG_PARALLEL; operators[1].snapshot.logseq_min = 1u; operators[1].snapshot.logseq_max = 10u; operators[1].params.tgk_traversal.direction = 2u; operators[1].params.tgk_traversal.traversal_depth = 3u; operators[1].params.tgk_traversal.start_node_id = 42u; operators[1].input_count = 1u; operators[1].inputs[0] = 1u; plan.plan_version = AMDUAT_ASL_TGK_EXEC_PLAN_VERSION; plan.operator_count = 2u; plan.operators = operators; if (!amduat_enc_asl_tgk_exec_plan_encode_v1(&plan, &encoded)) { fprintf(stderr, "encode failed\n"); return exit_code; } if (!amduat_enc_asl_tgk_exec_plan_decode_v1(encoded, &decoded)) { fprintf(stderr, "decode failed\n"); goto cleanup; } if (decoded.plan_version != plan.plan_version || decoded.operator_count != plan.operator_count) { fprintf(stderr, "header mismatch\n"); goto cleanup_decoded; } if (decoded.operators[1].op_type != operators[1].op_type || decoded.operators[1].params.tgk_traversal.direction != 2u || decoded.operators[1].params.tgk_traversal.traversal_depth != 3u || decoded.operators[1].params.tgk_traversal.start_node_id != 42u) { fprintf(stderr, "operator fields mismatch\n"); goto cleanup_decoded; } if (decoded.operators[1].input_count != 1u || decoded.operators[1].inputs[0] != 1u) { fprintf(stderr, "inputs mismatch\n"); goto cleanup_decoded; } exit_code = 0; cleanup_decoded: amduat_enc_asl_tgk_exec_plan_free(&decoded); cleanup: free((void *)encoded.data); return exit_code; } static int test_invalid_input_ref(void) { amduat_asl_tgk_exec_operator_def_t operators[1]; amduat_asl_tgk_exec_plan_t plan; amduat_octets_t encoded; int exit_code = 1; size_t op_offset; size_t input_offset; memset(operators, 0, sizeof(operators)); fill_default_params(&operators[0].params); operators[0].op_id = 1u; operators[0].op_type = AMDUAT_ASL_TGK_EXEC_OP_SEGMENT_SCAN; operators[0].input_count = 0u; plan.plan_version = AMDUAT_ASL_TGK_EXEC_PLAN_VERSION; plan.operator_count = 1u; plan.operators = operators; if (!amduat_enc_asl_tgk_exec_plan_encode_v1(&plan, &encoded)) { fprintf(stderr, "encode failed\n"); return exit_code; } op_offset = k_plan_header_size; if (encoded.len < op_offset + k_input_offset + 4u) { fprintf(stderr, "encoded buffer too small\n"); goto cleanup; } store_u32_le((uint8_t *)encoded.data + op_offset + k_params_size + 28u, 1u); input_offset = op_offset + k_input_offset; store_u32_le((uint8_t *)encoded.data + input_offset, 99u); if (amduat_enc_asl_tgk_exec_plan_decode_v1(encoded, &(amduat_asl_tgk_exec_plan_t){0})) { fprintf(stderr, "decode unexpectedly succeeded\n"); goto cleanup; } exit_code = 0; cleanup: free((void *)encoded.data); return exit_code; } static int test_truncated_decode(void) { amduat_asl_tgk_exec_operator_def_t operators[1]; amduat_asl_tgk_exec_plan_t plan; amduat_octets_t encoded; amduat_octets_t truncated; int exit_code = 1; memset(operators, 0, sizeof(operators)); fill_default_params(&operators[0].params); operators[0].op_id = 1u; operators[0].op_type = AMDUAT_ASL_TGK_EXEC_OP_SEGMENT_SCAN; plan.plan_version = AMDUAT_ASL_TGK_EXEC_PLAN_VERSION; plan.operator_count = 1u; plan.operators = operators; if (!amduat_enc_asl_tgk_exec_plan_encode_v1(&plan, &encoded)) { fprintf(stderr, "encode failed\n"); return exit_code; } truncated = amduat_octets(encoded.data, encoded.len - 1u); if (amduat_enc_asl_tgk_exec_plan_decode_v1(truncated, &(amduat_asl_tgk_exec_plan_t){0})) { fprintf(stderr, "decode unexpectedly succeeded\n"); goto cleanup; } exit_code = 0; cleanup: free((void *)encoded.data); return exit_code; } static int test_invalid_input_count(void) { amduat_asl_tgk_exec_operator_def_t operators[1]; amduat_asl_tgk_exec_plan_t plan; amduat_octets_t encoded; int exit_code = 1; size_t op_offset; size_t input_count_offset; memset(operators, 0, sizeof(operators)); fill_default_params(&operators[0].params); operators[0].op_id = 1u; operators[0].op_type = AMDUAT_ASL_TGK_EXEC_OP_SEGMENT_SCAN; plan.plan_version = AMDUAT_ASL_TGK_EXEC_PLAN_VERSION; plan.operator_count = 1u; plan.operators = operators; if (!amduat_enc_asl_tgk_exec_plan_encode_v1(&plan, &encoded)) { fprintf(stderr, "encode failed\n"); return exit_code; } op_offset = k_plan_header_size; input_count_offset = op_offset + k_params_size + 28u; if (encoded.len < input_count_offset + 4u) { fprintf(stderr, "encoded buffer too small\n"); goto cleanup; } store_u32_le((uint8_t *)encoded.data + input_count_offset, 9u); if (amduat_enc_asl_tgk_exec_plan_decode_v1(encoded, &(amduat_asl_tgk_exec_plan_t){0})) { fprintf(stderr, "decode unexpectedly succeeded\n"); goto cleanup; } exit_code = 0; cleanup: free((void *)encoded.data); return exit_code; } static int test_invalid_snapshot_range(void) { amduat_asl_tgk_exec_operator_def_t operators[1]; amduat_asl_tgk_exec_plan_t plan; memset(operators, 0, sizeof(operators)); fill_default_params(&operators[0].params); operators[0].op_id = 1u; operators[0].op_type = AMDUAT_ASL_TGK_EXEC_OP_SEGMENT_SCAN; operators[0].snapshot.logseq_min = 10u; operators[0].snapshot.logseq_max = 1u; plan.plan_version = AMDUAT_ASL_TGK_EXEC_PLAN_VERSION; plan.operator_count = 1u; plan.operators = operators; if (amduat_enc_asl_tgk_exec_plan_encode_v1(&plan, &(amduat_octets_t){0})) { fprintf(stderr, "encode unexpectedly succeeded\n"); return 1; } return 0; } static int test_fixture_plan0(void) { char path[512]; uint8_t *bytes = NULL; size_t len = 0u; amduat_asl_tgk_exec_plan_t plan; int exit_code = 1; if (!build_fixture_path(path, sizeof(path))) { fprintf(stderr, "fixture path build failed\n"); return exit_code; } if (!read_file(path, &bytes, &len)) { fprintf(stderr, "fixture read failed: %s\n", path); return exit_code; } if (!amduat_enc_asl_tgk_exec_plan_decode_v1(amduat_octets(bytes, len), &plan)) { fprintf(stderr, "fixture decode failed\n"); goto cleanup; } if (plan.plan_version != AMDUAT_ASL_TGK_EXEC_PLAN_VERSION || plan.operator_count != 1u || plan.operators[0].op_type != AMDUAT_ASL_TGK_EXEC_OP_SEGMENT_SCAN || plan.operators[0].snapshot.logseq_max != 10u) { fprintf(stderr, "fixture contents mismatch\n"); goto cleanup_plan; } exit_code = 0; cleanup_plan: amduat_enc_asl_tgk_exec_plan_free(&plan); cleanup: free(bytes); return exit_code; } int main(void) { if (test_round_trip() != 0) { return 1; } if (test_invalid_input_ref() != 0) { return 1; } if (test_truncated_decode() != 0) { return 1; } if (test_invalid_input_count() != 0) { return 1; } if (test_invalid_snapshot_range() != 0) { return 1; } return test_fixture_plan0(); }