e7738de6d2
CI / Deep Native Runtime Cases (1/6) (push) Has been skipped
CI / Native Preflight (push) Failing after 1s
CI / Native Runtime Cases (1/2) (push) Failing after 0s
CI / Native Runtime Cases (2/2) (push) Failing after 1s
CI / Native Metadata Reports (push) Failing after 0s
CI / Native Direct Backend Artifacts (push) Failing after 0s
CI / Native Sanitizer Smoke (push) Failing after 1s
CI / Command Contract Snapshots (push) Failing after 1s
CI / Deep Conformance Suite (push) Has been skipped
CI / Graph Build Perf (push) Failing after 1s
CI / Deep Native Preflight (push) Has been skipped
CI / Deep Native Runtime Cases (2/6) (push) Has been skipped
CI / Deep Native Runtime Cases (3/6) (push) Has been skipped
CI / Conformance Suite (push) Failing after 1s
CI / Workspace Checks (push) Failing after 0s
CI / Deep Native Runtime Cases (5/6) (push) Has been skipped
CI / Deep Native Runtime Cases (6/6) (push) Has been skipped
CI / Deep Native Runtime Cases (4/6) (push) Has been skipped
CI / Deep Graph Build Perf (push) Has been skipped
781 lines
38 KiB
C
781 lines
38 KiB
C
#include "program_graph_format.h"
|
|
#include "program_graph_lower.h"
|
|
#include "program_graph_projection.h"
|
|
#include "program_graph_store_binary.h"
|
|
|
|
#include <stdint.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static void expect(int ok, const char *message);
|
|
|
|
void *z_checked_malloc(size_t size) {
|
|
void *ptr = malloc(size ? size : 1);
|
|
if (ptr) return ptr;
|
|
fprintf(stderr, "out of memory\n");
|
|
exit(1);
|
|
}
|
|
|
|
void *z_checked_calloc(size_t count, size_t item_size) {
|
|
void *ptr = calloc(count ? count : 1, item_size ? item_size : 1);
|
|
if (ptr) return ptr;
|
|
fprintf(stderr, "out of memory\n");
|
|
exit(1);
|
|
}
|
|
|
|
void *z_checked_reallocarray(void *ptr, size_t count, size_t item_size) {
|
|
void *next = realloc(ptr, (count ? count : 1) * (item_size ? item_size : 1));
|
|
if (next) return next;
|
|
fprintf(stderr, "out of memory\n");
|
|
exit(1);
|
|
}
|
|
|
|
size_t z_grow_capacity(size_t current, size_t required, size_t initial) {
|
|
size_t next = current ? current : initial;
|
|
while (next < required) next *= 2;
|
|
return next;
|
|
}
|
|
|
|
char *z_strdup(const char *text) {
|
|
size_t len = strlen(text ? text : "");
|
|
return z_strndup(text ? text : "", len);
|
|
}
|
|
|
|
char *z_strndup(const char *text, size_t len) {
|
|
char *copy = z_checked_malloc(len + 1);
|
|
memcpy(copy, text ? text : "", len + 1);
|
|
copy[len] = 0;
|
|
return copy;
|
|
}
|
|
|
|
bool z_write_file(const char *path, const char *text, ZDiag *diag) {
|
|
FILE *file = fopen(path, "wb");
|
|
if (!file) {
|
|
if (diag) snprintf(diag->message, sizeof(diag->message), "failed to write test graph");
|
|
return false;
|
|
}
|
|
fputs(text ? text : "", file);
|
|
fclose(file);
|
|
return true;
|
|
}
|
|
|
|
void zbuf_init(ZBuf *buf) { *buf = (ZBuf){0}; }
|
|
void zbuf_free(ZBuf *buf) {
|
|
free(buf->data);
|
|
*buf = (ZBuf){0};
|
|
}
|
|
|
|
void zbuf_append_char(ZBuf *buf, char ch) {
|
|
if (buf->len + 1 >= buf->cap) {
|
|
buf->cap = z_grow_capacity(buf->cap, buf->len + 2, 64);
|
|
buf->data = z_checked_reallocarray(buf->data, buf->cap, 1);
|
|
}
|
|
buf->data[buf->len++] = ch;
|
|
buf->data[buf->len] = 0;
|
|
}
|
|
|
|
void zbuf_append(ZBuf *buf, const char *text) {
|
|
for (const char *p = text ? text : ""; *p; p++) zbuf_append_char(buf, *p);
|
|
}
|
|
|
|
void zbuf_appendf(ZBuf *buf, const char *fmt, ...) {
|
|
char stack[256];
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
int len = vsnprintf(stack, sizeof(stack), fmt, args);
|
|
va_end(args);
|
|
expect(len >= 0 && (size_t)len < sizeof(stack), "formatted test buffer overflow");
|
|
zbuf_append(buf, stack);
|
|
}
|
|
|
|
static void expect(int ok, const char *message) {
|
|
if (ok) return;
|
|
fprintf(stderr, "%s\n", message);
|
|
exit(1);
|
|
}
|
|
|
|
static uint64_t read_le_u64(const unsigned char *bytes, size_t offset, size_t len) {
|
|
expect(bytes != NULL && offset <= len && len - offset >= 8, "binary fixture read out of range");
|
|
uint64_t value = 0;
|
|
for (unsigned i = 0; i < 8; i++) value |= (uint64_t)bytes[offset + i] << (i * 8);
|
|
return value;
|
|
}
|
|
|
|
static void write_le_u64(unsigned char *bytes, size_t offset, size_t len, uint64_t value) {
|
|
expect(bytes != NULL && offset <= len && len - offset >= 8, "binary fixture write out of range");
|
|
for (unsigned i = 0; i < 8; i++) bytes[offset + i] = (unsigned char)((value >> (i * 8)) & 0xffu);
|
|
}
|
|
|
|
static unsigned char *copy_binary_fixture(const ZBuf *binary) {
|
|
unsigned char *copy = z_checked_malloc(binary->len);
|
|
memcpy(copy, binary->data, binary->len);
|
|
return copy;
|
|
}
|
|
|
|
static void expect_binary_store_rejected(const unsigned char *bytes, size_t len, const char *message) {
|
|
ZProgramGraphStore parsed;
|
|
ZDiag diag = {0};
|
|
expect(!z_program_graph_store_parse_binary("corrupt-zero.graph", bytes, len, &parsed, &diag), message);
|
|
expect(strstr(diag.message, "invalid") != NULL || strstr(diag.message, "failed") != NULL, "binary rejection reported wrong diagnostic");
|
|
}
|
|
|
|
enum {
|
|
BINARY_SOURCE_COUNT_OFFSET = 24,
|
|
BINARY_PROJECTION_COUNT_OFFSET = 32,
|
|
BINARY_NODE_COUNT_OFFSET = 40,
|
|
BINARY_EDGE_COUNT_OFFSET = 48,
|
|
BINARY_STRING_BYTES_OFFSET = 64,
|
|
BINARY_MODULE_IDENTITY_REF_OFFSET = 72,
|
|
};
|
|
|
|
static void set_node(ZProgramGraphNode *node, const char *id, ZProgramGraphNodeKind kind, const char *name, const char *type) {
|
|
node->id = z_strdup(id);
|
|
node->kind = kind;
|
|
node->name = name ? z_strdup(name) : NULL;
|
|
node->type = type ? z_strdup(type) : NULL;
|
|
node->path = z_strdup("program-graph-smoke.0");
|
|
node->line = 1;
|
|
node->column = 1;
|
|
}
|
|
|
|
static void set_edge(ZProgramGraphEdge *edge, const char *from, const char *to, const char *kind, ZProgramGraphEdgeTarget target, size_t order) {
|
|
edge->from = z_strdup(from);
|
|
edge->to = z_strdup(to);
|
|
edge->kind = z_strdup(kind);
|
|
edge->target = target;
|
|
edge->order = order;
|
|
}
|
|
|
|
static void expect_binary_store_corruption_rejected(const ZProgramGraph *graph) {
|
|
ZProgramGraphStore projections;
|
|
z_program_graph_store_init(&projections);
|
|
projections.projection_paths = z_checked_calloc(1, sizeof(char *));
|
|
projections.projection_texts = z_checked_calloc(1, sizeof(char *));
|
|
projections.projection_cap = 1;
|
|
projections.projection_len = 1;
|
|
projections.projection_paths[0] = z_strdup("program-graph-smoke.0");
|
|
projections.projection_texts[0] = z_strdup("pub fn main(world: World) -> Void raises {\n}\n");
|
|
|
|
ZBuf binary;
|
|
zbuf_init(&binary);
|
|
z_program_graph_store_append_binary(&binary, graph, &projections);
|
|
expect(z_program_graph_store_bytes_are_binary((const unsigned char *)binary.data, binary.len), "binary store fixture did not use binary magic");
|
|
|
|
ZProgramGraphStore parsed;
|
|
ZDiag valid_diag = {0};
|
|
expect(z_program_graph_store_parse_binary("valid-zero.graph", (const unsigned char *)binary.data, binary.len, &parsed, &valid_diag), valid_diag.message);
|
|
z_program_graph_store_free(&parsed);
|
|
|
|
uint64_t string_bytes = read_le_u64((const unsigned char *)binary.data, BINARY_STRING_BYTES_OFFSET, binary.len);
|
|
uint64_t module_identity_offset = read_le_u64((const unsigned char *)binary.data, BINARY_MODULE_IDENTITY_REF_OFFSET, binary.len);
|
|
uint64_t module_identity_len = read_le_u64((const unsigned char *)binary.data, BINARY_MODULE_IDENTITY_REF_OFFSET + 8, binary.len);
|
|
expect(string_bytes <= (uint64_t)binary.len, "binary fixture has invalid string table size");
|
|
expect(module_identity_len > 2, "binary fixture module identity too small to corrupt");
|
|
size_t strings_offset = binary.len - (size_t)string_bytes;
|
|
expect(module_identity_offset + 1 < string_bytes, "binary fixture module identity offset out of range");
|
|
|
|
unsigned char *embedded_nul = copy_binary_fixture(&binary);
|
|
embedded_nul[strings_offset + (size_t)module_identity_offset + 1] = 0;
|
|
expect_binary_store_rejected(embedded_nul, binary.len, "binary store with embedded NUL parsed");
|
|
free(embedded_nul);
|
|
|
|
unsigned char *too_many_sources = copy_binary_fixture(&binary);
|
|
write_le_u64(too_many_sources, BINARY_SOURCE_COUNT_OFFSET, binary.len, 100001u);
|
|
expect_binary_store_rejected(too_many_sources, binary.len, "binary store with oversized source count parsed");
|
|
free(too_many_sources);
|
|
|
|
unsigned char *too_many_projections = copy_binary_fixture(&binary);
|
|
write_le_u64(too_many_projections, BINARY_PROJECTION_COUNT_OFFSET, binary.len, 100001u);
|
|
expect_binary_store_rejected(too_many_projections, binary.len, "binary store with oversized projection count parsed");
|
|
free(too_many_projections);
|
|
|
|
unsigned char *too_many_nodes = copy_binary_fixture(&binary);
|
|
write_le_u64(too_many_nodes, BINARY_NODE_COUNT_OFFSET, binary.len, 1000001u);
|
|
expect_binary_store_rejected(too_many_nodes, binary.len, "binary store with oversized node count parsed");
|
|
free(too_many_nodes);
|
|
|
|
unsigned char *too_many_edges = copy_binary_fixture(&binary);
|
|
write_le_u64(too_many_edges, BINARY_EDGE_COUNT_OFFSET, binary.len, 4000001u);
|
|
expect_binary_store_rejected(too_many_edges, binary.len, "binary store with oversized edge count parsed");
|
|
free(too_many_edges);
|
|
|
|
unsigned char *too_many_string_bytes = copy_binary_fixture(&binary);
|
|
write_le_u64(too_many_string_bytes, BINARY_STRING_BYTES_OFFSET, binary.len, 256u * 1024u * 1024u + 1u);
|
|
expect_binary_store_rejected(too_many_string_bytes, binary.len, "binary store with oversized string table parsed");
|
|
free(too_many_string_bytes);
|
|
|
|
zbuf_free(&binary);
|
|
z_program_graph_store_free(&projections);
|
|
}
|
|
|
|
static void expect_binary_store_rejects_user_std_basename_without_projection(void) {
|
|
ZProgramGraph graph;
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(1, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 1;
|
|
graph.node_cap = 1;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "term", NULL);
|
|
free(graph.nodes[0].path);
|
|
graph.nodes[0].path = z_strdup("src/term.0");
|
|
z_program_graph_finalize_identities(&graph);
|
|
|
|
ZBuf binary;
|
|
zbuf_init(&binary);
|
|
z_program_graph_store_append_binary(&binary, &graph, NULL);
|
|
ZProgramGraphStore parsed;
|
|
ZDiag diag = {0};
|
|
expect(!z_program_graph_store_parse_binary("user-std-basename.graph", (const unsigned char *)binary.data, binary.len, &parsed, &diag),
|
|
"binary store accepted user source path matching std basename without projection");
|
|
expect(strstr(diag.message, "projection table") != NULL || strstr(diag.message, "source table") != NULL,
|
|
"binary store basename collision reported wrong diagnostic");
|
|
|
|
zbuf_free(&binary);
|
|
z_program_graph_free(&graph);
|
|
}
|
|
|
|
static void expect_binary_fast_sync_rejects_empty_projection_table(const ZProgramGraph *graph) {
|
|
ZBuf binary;
|
|
zbuf_init(&binary);
|
|
z_program_graph_store_append_binary(&binary, graph, NULL);
|
|
|
|
char storage_path[128];
|
|
snprintf(storage_path, sizeof(storage_path), "/tmp/zero-program-graph-empty-projection-%p.graph", (void *)graph);
|
|
ZDiag write_diag = {0};
|
|
expect(z_write_binary_file(storage_path, (const unsigned char *)binary.data, binary.len, &write_diag), write_diag.message);
|
|
|
|
ZProgramGraphProjectionSourceSync sync = Z_PROGRAM_GRAPH_PROJECTION_SYNC_DIVERGED;
|
|
expect(!z_program_graph_projection_source_sync_state_binary_fast(storage_path, ".", &sync),
|
|
"binary fast sync accepted store with empty projection table");
|
|
|
|
remove(storage_path);
|
|
zbuf_free(&binary);
|
|
}
|
|
|
|
static void expect_lowered_program(void) {
|
|
ZProgramGraph graph;
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(3, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 3;
|
|
graph.node_cap = 3;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "main", "Void");
|
|
graph.nodes[1].is_public = true;
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
graph.edges = z_checked_calloc(2, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 2;
|
|
graph.edge_cap = 2;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
z_program_graph_finalize_identities(&graph);
|
|
|
|
ZProgramGraphValidation validation = {0};
|
|
expect(z_program_graph_validate(&graph, &validation), "lowerable graph failed validation");
|
|
Program program = {0};
|
|
ZDiag diag = {0};
|
|
expect(z_program_graph_lower_to_program(&graph, &program, &diag), diag.message);
|
|
expect(program.functions.len == 1, "lowered graph reported wrong function count");
|
|
expect(strcmp(program.functions.items[0].name, "main") == 0, "lowered function kept wrong name");
|
|
expect(strcmp(program.functions.items[0].return_type, "Void") == 0, "lowered function kept wrong return type");
|
|
expect(program.functions.items[0].is_public, "lowered function lost public flag");
|
|
expect(program.functions.items[0].body.len == 0, "lowered empty body gained statements");
|
|
z_free_program(&program);
|
|
z_program_graph_free(&graph);
|
|
}
|
|
|
|
static void expect_import_lowering_failure(const char *module, const char *alias, const char *message) {
|
|
ZProgramGraph graph;
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(4, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 4;
|
|
graph.node_cap = 4;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_IMPORT, module, NULL);
|
|
graph.nodes[1].value = alias ? z_strdup(alias) : NULL;
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_FUNCTION, "main", "Void");
|
|
graph.nodes[2].is_public = true;
|
|
set_node(&graph.nodes[3], "#000004", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
graph.edges = z_checked_calloc(3, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 3;
|
|
graph.edge_cap = 3;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "import", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000001", "#000003", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[2], "#000003", "#000004", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
z_program_graph_finalize_identities(&graph);
|
|
|
|
ZProgramGraphValidation validation = {0};
|
|
expect(z_program_graph_validate(&graph, &validation), "invalid import test graph should remain shape-valid");
|
|
Program program = {0};
|
|
ZDiag diag = {0};
|
|
expect(!z_program_graph_lower_to_program(&graph, &program, &diag), "invalid import graph lowered successfully");
|
|
expect(strstr(diag.message, message) != NULL, "invalid import graph reported wrong diagnostic");
|
|
z_program_graph_free(&graph);
|
|
}
|
|
|
|
static void expect_lower_rejects_bad_imports(void) {
|
|
expect_import_lowering_failure("+", NULL, "import module");
|
|
expect_import_lowering_failure("pub", NULL, "import module");
|
|
expect_import_lowering_failure("missing", NULL, "target module is missing");
|
|
expect_import_lowering_failure("std.mem", "+", "import alias");
|
|
expect_import_lowering_failure("std.mem", "pub", "import alias");
|
|
}
|
|
|
|
static void expect_lower_rejects_reserved_function_name(void) {
|
|
ZProgramGraph graph;
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(3, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 3;
|
|
graph.node_cap = 3;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "pub", "Void");
|
|
graph.nodes[1].is_public = true;
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
graph.edges = z_checked_calloc(2, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 2;
|
|
graph.edge_cap = 2;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
z_program_graph_finalize_identities(&graph);
|
|
|
|
ZProgramGraphValidation validation = {0};
|
|
expect(z_program_graph_validate(&graph, &validation), "reserved function name graph should remain shape-valid");
|
|
Program program = {0};
|
|
ZDiag diag = {0};
|
|
expect(!z_program_graph_lower_to_program(&graph, &program, &diag), "reserved function name lowered successfully");
|
|
expect(strstr(diag.message, "function name") != NULL, "reserved function name reported wrong diagnostic");
|
|
z_program_graph_free(&graph);
|
|
}
|
|
|
|
static void expect_lower_rejects_internal_function_name(void) {
|
|
ZProgramGraph graph;
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(3, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 3;
|
|
graph.node_cap = 3;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "__zero_bad", "Void");
|
|
graph.nodes[1].is_public = true;
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
graph.edges = z_checked_calloc(2, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 2;
|
|
graph.edge_cap = 2;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
z_program_graph_finalize_identities(&graph);
|
|
|
|
ZProgramGraphValidation validation = {0};
|
|
expect(z_program_graph_validate(&graph, &validation), "internal function name graph should remain shape-valid");
|
|
Program program = {0};
|
|
ZDiag diag = {0};
|
|
expect(!z_program_graph_lower_to_program(&graph, &program, &diag), "internal function name lowered successfully");
|
|
expect(strstr(diag.message, "reserved compiler-internal") != NULL, "internal function name reported wrong diagnostic");
|
|
z_program_graph_free(&graph);
|
|
}
|
|
|
|
static void expect_lower_allows_embedded_std_internal_function_name(void) {
|
|
ZProgramGraph graph;
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(3, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 3;
|
|
graph.node_cap = 3;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "std.math", NULL);
|
|
free(graph.nodes[0].path);
|
|
graph.nodes[0].path = z_strdup("std/math.0");
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "__zero_std_math_local", "Void");
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
graph.edges = z_checked_calloc(2, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 2;
|
|
graph.edge_cap = 2;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
z_program_graph_finalize_identities(&graph);
|
|
|
|
ZProgramGraphValidation validation = {0};
|
|
expect(z_program_graph_validate(&graph, &validation), "embedded std internal function graph should remain shape-valid");
|
|
Program program = {0};
|
|
ZDiag diag = {0};
|
|
expect(z_program_graph_lower_to_program(&graph, &program, &diag), diag.message);
|
|
expect(program.functions.len == 1, "embedded std internal function was not lowered");
|
|
expect(strcmp(program.functions.items[0].name, "__zero_std_math_local") == 0, "embedded std internal function name changed");
|
|
z_free_program(&program);
|
|
z_program_graph_free(&graph);
|
|
}
|
|
|
|
static void expect_lower_rejects_reserved_call_name(void) {
|
|
ZProgramGraph graph;
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(5, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 5;
|
|
graph.node_cap = 5;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "main", "Void");
|
|
graph.nodes[1].is_public = true;
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
set_node(&graph.nodes[3], "#000004", Z_PROGRAM_GRAPH_NODE_EXPRESSION_STATEMENT, NULL, NULL);
|
|
set_node(&graph.nodes[4], "#000005", Z_PROGRAM_GRAPH_NODE_CALL, "pub", NULL);
|
|
graph.edges = z_checked_calloc(4, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 4;
|
|
graph.edge_cap = 4;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[2], "#000003", "#000004", "statement", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[3], "#000004", "#000005", "expr", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
z_program_graph_finalize_identities(&graph);
|
|
|
|
ZProgramGraphValidation validation = {0};
|
|
expect(z_program_graph_validate(&graph, &validation), "reserved call name graph should remain shape-valid");
|
|
Program program = {0};
|
|
ZDiag diag = {0};
|
|
expect(!z_program_graph_lower_to_program(&graph, &program, &diag), "reserved call name lowered successfully");
|
|
expect(strstr(diag.message, "call callee") != NULL, "reserved call name reported wrong diagnostic");
|
|
z_program_graph_free(&graph);
|
|
}
|
|
|
|
static void expect_validation_code(ZProgramGraph *graph, const char *code, const char *message) {
|
|
z_program_graph_finalize_identities(graph);
|
|
ZProgramGraphValidation validation = {0};
|
|
expect(!z_program_graph_validate(graph, &validation), message);
|
|
expect(strcmp(validation.code, code) == 0, "validation reported wrong code");
|
|
}
|
|
|
|
static void expect_validation_allows_unconstrained_type_params(void) {
|
|
ZProgramGraph graph;
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(5, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 5;
|
|
graph.node_cap = 5;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_SHAPE, "Box", NULL);
|
|
graph.nodes[1].value = z_strdup("auto");
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_PARAM, "T", NULL);
|
|
set_node(&graph.nodes[3], "#000004", Z_PROGRAM_GRAPH_NODE_FIELD, "value", "T");
|
|
set_node(&graph.nodes[4], "#000005", Z_PROGRAM_GRAPH_NODE_TYPE_REF, NULL, "T");
|
|
graph.edges = z_checked_calloc(4, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 4;
|
|
graph.edge_cap = 4;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "shape", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "typeParam", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[2], "#000002", "#000004", "field", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[3], "#000004", "#000005", "type", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
z_program_graph_finalize_identities(&graph);
|
|
|
|
ZProgramGraphValidation validation = {0};
|
|
expect(z_program_graph_validate(&graph, &validation), "unconstrained type param failed validation");
|
|
z_program_graph_free(&graph);
|
|
}
|
|
|
|
static void expect_validation_rejects_malformed_graphs(void) {
|
|
ZProgramGraph graph;
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(4, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 4;
|
|
graph.node_cap = 4;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "main", "Void");
|
|
graph.nodes[1].is_public = true;
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
set_node(&graph.nodes[3], "#000004", Z_PROGRAM_GRAPH_NODE_CHECK, NULL, NULL);
|
|
graph.edges = z_checked_calloc(4, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 4;
|
|
graph.edge_cap = 4;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[2], "#000003", "#000004", "statement", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[3], "#000003", "#000004", "statement", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 2);
|
|
expect_validation_code(&graph, "GRF013", "sparse ordered statement edges validated");
|
|
z_program_graph_free(&graph);
|
|
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(3, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 3;
|
|
graph.node_cap = 3;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "main", "Void");
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
graph.edges = z_checked_calloc(2, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 2;
|
|
graph.edge_cap = 2;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "statement", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
expect_validation_code(&graph, "GRF012", "invalid module child edge validated");
|
|
z_program_graph_free(&graph);
|
|
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(2, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 2;
|
|
graph.node_cap = 2;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "main", "Void");
|
|
graph.edges = z_checked_calloc(1, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 1;
|
|
graph.edge_cap = 1;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
expect_validation_code(&graph, "GRF016", "function without body validated");
|
|
z_program_graph_free(&graph);
|
|
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(4, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 4;
|
|
graph.node_cap = 4;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "main", "Void");
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_PARAM, "world", NULL);
|
|
set_node(&graph.nodes[3], "#000004", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
graph.edges = z_checked_calloc(3, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 3;
|
|
graph.edge_cap = 3;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "param", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[2], "#000002", "#000004", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
expect_validation_code(&graph, "GRF014", "value param without type validated");
|
|
z_program_graph_free(&graph);
|
|
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(1, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 1;
|
|
graph.node_cap = 1;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_LITERAL, NULL, NULL);
|
|
expect_validation_code(&graph, "GRF014", "literal without value validated");
|
|
z_program_graph_free(&graph);
|
|
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(5, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 5;
|
|
graph.node_cap = 5;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "main", "Void");
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
set_node(&graph.nodes[3], "#000004", Z_PROGRAM_GRAPH_NODE_CHECK, NULL, NULL);
|
|
set_node(&graph.nodes[4], "#000005", Z_PROGRAM_GRAPH_NODE_LITERAL, NULL, NULL);
|
|
graph.nodes[4].value = z_strdup("true");
|
|
graph.edges = z_checked_calloc(4, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 4;
|
|
graph.edge_cap = 4;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[2], "#000003", "#000004", "statement", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[3], "#000004", "#000005", "left", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
expect_validation_code(&graph, "GRF016", "statement check with left edge validated");
|
|
z_program_graph_free(&graph);
|
|
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(6, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 6;
|
|
graph.node_cap = 6;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "main", "Void");
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
set_node(&graph.nodes[3], "#000004", Z_PROGRAM_GRAPH_NODE_LET, "value", NULL);
|
|
set_node(&graph.nodes[4], "#000005", Z_PROGRAM_GRAPH_NODE_CHECK, NULL, NULL);
|
|
set_node(&graph.nodes[5], "#000006", Z_PROGRAM_GRAPH_NODE_LITERAL, NULL, NULL);
|
|
graph.nodes[5].value = z_strdup("true");
|
|
graph.edges = z_checked_calloc(5, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 5;
|
|
graph.edge_cap = 5;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[2], "#000003", "#000004", "statement", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[3], "#000004", "#000005", "expr", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[4], "#000005", "#000006", "expr", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
expect_validation_code(&graph, "GRF016", "expression check with expr edge validated");
|
|
z_program_graph_free(&graph);
|
|
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(7, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 7;
|
|
graph.node_cap = 7;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "main", "Void");
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
set_node(&graph.nodes[3], "#000004", Z_PROGRAM_GRAPH_NODE_CHECK, NULL, NULL);
|
|
set_node(&graph.nodes[4], "#000005", Z_PROGRAM_GRAPH_NODE_INDEX_ACCESS, NULL, NULL);
|
|
set_node(&graph.nodes[5], "#000006", Z_PROGRAM_GRAPH_NODE_IDENTIFIER, "world", NULL);
|
|
set_node(&graph.nodes[6], "#000007", Z_PROGRAM_GRAPH_NODE_LITERAL, NULL, NULL);
|
|
graph.nodes[6].value = z_strdup("0");
|
|
graph.edges = z_checked_calloc(6, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 6;
|
|
graph.edge_cap = 6;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[2], "#000003", "#000004", "statement", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[3], "#000004", "#000005", "expr", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[4], "#000005", "#000006", "left", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[5], "#000005", "#000007", "right", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
expect_validation_code(&graph, "GRF016", "right edge at order zero validated");
|
|
z_program_graph_free(&graph);
|
|
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(5, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 5;
|
|
graph.node_cap = 5;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "main", "u8");
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
set_node(&graph.nodes[3], "#000004", Z_PROGRAM_GRAPH_NODE_RETURN, NULL, NULL);
|
|
set_node(&graph.nodes[4], "#000005", Z_PROGRAM_GRAPH_NODE_RESCUE, NULL, "u8");
|
|
graph.edges = z_checked_calloc(3, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 3;
|
|
graph.edge_cap = 3;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[2], "#000003", "#000004", "statement", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
expect_validation_code(&graph, "GRF014", "rescue without binding name validated");
|
|
z_program_graph_free(&graph);
|
|
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(5, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 5;
|
|
graph.node_cap = 5;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "main", "u8");
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
set_node(&graph.nodes[3], "#000004", Z_PROGRAM_GRAPH_NODE_RETURN, NULL, NULL);
|
|
set_node(&graph.nodes[4], "#000005", Z_PROGRAM_GRAPH_NODE_CAST, NULL, NULL);
|
|
graph.edges = z_checked_calloc(3, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 3;
|
|
graph.edge_cap = 3;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[2], "#000003", "#000004", "statement", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
expect_validation_code(&graph, "GRF014", "cast without target type validated");
|
|
z_program_graph_free(&graph);
|
|
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(7, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 7;
|
|
graph.node_cap = 7;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "main", "Void");
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
set_node(&graph.nodes[3], "#000004", Z_PROGRAM_GRAPH_NODE_RETURN, NULL, NULL);
|
|
set_node(&graph.nodes[4], "#000005", Z_PROGRAM_GRAPH_NODE_SLICE, NULL, NULL);
|
|
set_node(&graph.nodes[5], "#000006", Z_PROGRAM_GRAPH_NODE_IDENTIFIER, "bytes", NULL);
|
|
set_node(&graph.nodes[6], "#000007", Z_PROGRAM_GRAPH_NODE_LITERAL, NULL, NULL);
|
|
graph.nodes[6].value = z_strdup("1");
|
|
graph.edges = z_checked_calloc(6, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 6;
|
|
graph.edge_cap = 6;
|
|
set_edge(&graph.edges[0], "#000001", "#000002", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[2], "#000003", "#000004", "statement", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[3], "#000004", "#000005", "expr", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[4], "#000005", "#000006", "left", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
set_edge(&graph.edges[5], "#000005", "#000007", "arg", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 2);
|
|
expect_validation_code(&graph, "GRF016", "slice arg outside supported order range validated");
|
|
z_program_graph_free(&graph);
|
|
}
|
|
|
|
int main(void) {
|
|
expect_lowered_program();
|
|
expect_lower_rejects_bad_imports();
|
|
expect_lower_rejects_reserved_function_name();
|
|
expect_lower_rejects_internal_function_name();
|
|
expect_lower_allows_embedded_std_internal_function_name();
|
|
expect_lower_rejects_reserved_call_name();
|
|
expect_validation_allows_unconstrained_type_params();
|
|
expect_validation_rejects_malformed_graphs();
|
|
|
|
ZProgramGraph graph;
|
|
z_program_graph_init(&graph);
|
|
graph.nodes = z_checked_calloc(3, sizeof(ZProgramGraphNode));
|
|
graph.node_len = 3;
|
|
graph.node_cap = 3;
|
|
set_node(&graph.nodes[0], "#000001", Z_PROGRAM_GRAPH_NODE_MODULE, "smoke", NULL);
|
|
set_node(&graph.nodes[1], "#000002", Z_PROGRAM_GRAPH_NODE_FUNCTION, "main", "Void");
|
|
set_node(&graph.nodes[2], "#000003", Z_PROGRAM_GRAPH_NODE_BLOCK, "body", NULL);
|
|
graph.edges = z_checked_calloc(2, sizeof(ZProgramGraphEdge));
|
|
graph.edge_len = 2;
|
|
graph.edge_cap = 2;
|
|
set_edge(&graph.edges[0], "#000001", "symbol:missing", "function", Z_PROGRAM_GRAPH_EDGE_TARGET_SYMBOL, 0);
|
|
set_edge(&graph.edges[1], "#000002", "#000003", "body", Z_PROGRAM_GRAPH_EDGE_TARGET_NODE, 0);
|
|
z_program_graph_finalize_identities(&graph);
|
|
|
|
ZProgramGraphValidation validation = {0};
|
|
expect(!z_program_graph_validate(&graph, &validation), "missing symbol target validated");
|
|
expect(strcmp(validation.code, "GRF005") == 0, "missing symbol target reported wrong code");
|
|
expect(strcmp(validation.edge_target, "symbol") == 0, "missing symbol target reported wrong domain");
|
|
|
|
free(graph.edges[0].to);
|
|
graph.edges[0].to = z_strdup(graph.nodes[1].symbol_id);
|
|
z_program_graph_finalize_identities(&graph);
|
|
expect(z_program_graph_validate(&graph, &validation), "valid symbol target failed validation");
|
|
expect(validation.state == Z_PROGRAM_GRAPH_VALIDATION_SHAPE_VALID, "valid graph reported wrong state");
|
|
expect_binary_store_corruption_rejected(&graph);
|
|
expect_binary_store_rejects_user_std_basename_without_projection();
|
|
expect_binary_fast_sync_rejects_empty_projection_table(&graph);
|
|
|
|
ZBuf dump;
|
|
zbuf_init(&dump);
|
|
z_program_graph_append_dump(&dump, &graph, &validation);
|
|
ZProgramGraph parsed;
|
|
ZDiag diag = {0};
|
|
expect(z_program_graph_parse_dump(dump.data, &parsed, &diag), diag.message);
|
|
ZProgramGraphValidation parsed_validation = {0};
|
|
expect(z_program_graph_validate(&parsed, &parsed_validation), "parsed graph failed validation");
|
|
ZBuf redump;
|
|
zbuf_init(&redump);
|
|
z_program_graph_append_dump(&redump, &parsed, &parsed_validation);
|
|
expect(strcmp(dump.data, redump.data) == 0, "parsed graph dump was not byte-stable");
|
|
|
|
char storage_path[128];
|
|
snprintf(storage_path, sizeof(storage_path), "/tmp/zero-program-graph-smoke-%p.graph", (void *)&graph);
|
|
ZDiag storage_diag = {0};
|
|
expect(z_program_graph_save(storage_path, &graph, &storage_diag), storage_diag.message);
|
|
ZProgramGraph loaded;
|
|
expect(z_program_graph_load(storage_path, &loaded, &storage_diag), storage_diag.message);
|
|
ZProgramGraphValidation loaded_validation = {0};
|
|
expect(z_program_graph_validate(&loaded, &loaded_validation), "loaded graph failed validation");
|
|
ZBuf loaded_dump;
|
|
zbuf_init(&loaded_dump);
|
|
z_program_graph_append_dump(&loaded_dump, &loaded, &loaded_validation);
|
|
expect(strcmp(dump.data, loaded_dump.data) == 0, "loaded graph dump was not byte-stable");
|
|
zbuf_free(&loaded_dump);
|
|
z_program_graph_free(&loaded);
|
|
remove(storage_path);
|
|
|
|
char *corrupted = z_strdup(dump.data);
|
|
char *corrupt_name = strstr(corrupted, "name:\"main\"");
|
|
expect(corrupt_name != NULL, "expected main function name in graph dump");
|
|
memcpy(corrupt_name, "name:\"fail\"", strlen("name:\"fail\""));
|
|
ZProgramGraph rejected;
|
|
ZDiag rejected_diag = {0};
|
|
expect(!z_program_graph_parse_dump(corrupted, &rejected, &rejected_diag), "corrupt graph content parsed");
|
|
expect(strstr(rejected_diag.message, "identities") != NULL, "corrupt graph content reported wrong diagnostic");
|
|
free(corrupted);
|
|
|
|
ZProgramGraph wrong_schema;
|
|
ZDiag wrong_schema_diag = {0};
|
|
expect(!z_program_graph_parse_dump("zero-graph v2\n", &wrong_schema, &wrong_schema_diag), "unknown schema parsed");
|
|
expect(strstr(wrong_schema_diag.message, "schema") != NULL, "unknown schema reported wrong diagnostic");
|
|
|
|
const char *failed_dump =
|
|
"zero-graph v1\n"
|
|
"origin source-text\n"
|
|
"module \"main\"\n"
|
|
"hash \"\"\n"
|
|
"validation \"decoded\" failed\n"
|
|
"diagnostic code:\"GRF001\" message:\"program graph construction failed\"\n";
|
|
ZProgramGraph failed_artifact;
|
|
ZDiag failed_artifact_diag = {0};
|
|
expect(!z_program_graph_parse_dump(failed_dump, &failed_artifact, &failed_artifact_diag), "failed validation artifact parsed");
|
|
expect(strstr(failed_artifact_diag.message, "failed validation") != NULL, "failed validation artifact reported wrong diagnostic");
|
|
|
|
ZBuf trailing_extra;
|
|
zbuf_init(&trailing_extra);
|
|
zbuf_append(&trailing_extra, dump.data);
|
|
zbuf_append(&trailing_extra, "\nextra\n");
|
|
ZProgramGraph trailing_artifact;
|
|
ZDiag trailing_artifact_diag = {0};
|
|
expect(!z_program_graph_parse_dump(trailing_extra.data, &trailing_artifact, &trailing_artifact_diag), "trailing content parsed");
|
|
expect(strstr(trailing_artifact_diag.message, "unexpected content") != NULL, "trailing content reported wrong diagnostic");
|
|
|
|
zbuf_free(&trailing_extra);
|
|
zbuf_free(&redump);
|
|
z_program_graph_free(&parsed);
|
|
zbuf_free(&dump);
|
|
z_program_graph_free(&graph);
|
|
puts("program graph smoke ok");
|
|
return 0;
|
|
}
|