const std = @import("std"); const testing = std.testing; const dependency_resolver = @import("src/dependency_resolver.zig"); const patterns = @import("src/patterns.zig"); test "flow: basic missing type detection" { const allocator = testing.allocator; // Simulate parsed declarations from SDL_gpu.h const decls = [_]patterns.Declaration{ // Defined: SDL_GPUDevice .{ .opaque_type = .{ .name = "SDL_GPUDevice", .doc_comment = null, }}, // Function references SDL_Window (not defined) .{ .function_decl = .{ .name = "SDL_ClaimWindow", .return_type = "bool", .params = &[_]patterns.ParamDecl{ .{ .name = "device", .type_name = "SDL_GPUDevice *" }, .{ .name = "window", .type_name = "SDL_Window *" }, }, .doc_comment = null, }}, }; var resolver = dependency_resolver.DependencyResolver.init(allocator); defer resolver.deinit(); try resolver.analyze(&decls); const missing = try resolver.getMissingTypes(allocator); defer { for (missing) |m| allocator.free(m); allocator.free(missing); } // Should find SDL_Window but not SDL_GPUDevice (it's defined) try testing.expectEqual(@as(usize, 1), missing.len); try testing.expectEqualStrings("SDL_Window", missing[0]); } test "flow: extractBaseType comprehensive" { const test_cases = [_]struct { input: []const u8, expected: []const u8, }{ .{ .input = "SDL_Window *", .expected = "SDL_Window" }, .{ .input = "*SDL_Window", .expected = "SDL_Window" }, .{ .input = "?*SDL_Window", .expected = "SDL_Window" }, .{ .input = "*const SDL_Rect", .expected = "SDL_Rect" }, .{ .input = "SDL_Rect *const", .expected = "SDL_Rect" }, .{ .input = "SDL_Buffer *const *", .expected = "SDL_Buffer" }, .{ .input = "?*?*SDL_Texture", .expected = "SDL_Texture" }, .{ .input = "[*c]const u8", .expected = "u8" }, .{ .input = "const SDL_FColor *", .expected = "SDL_FColor" }, .{ .input = "SDL_FColor", .expected = "SDL_FColor" }, }; for (test_cases) |tc| { const result = dependency_resolver.extractBaseType(tc.input); try testing.expectEqualStrings(tc.expected, result); } } test "flow: parseIncludes from source" { const allocator = testing.allocator; const source = \\#include \\#include \\ \\// Some code \\#include \\#include // Not SDL3 ; const includes = try dependency_resolver.parseIncludes(allocator, source); defer { for (includes) |inc| allocator.free(inc); allocator.free(includes); } try testing.expectEqual(@as(usize, 3), includes.len); try testing.expectEqualStrings("SDL_stdinc.h", includes[0]); try testing.expectEqualStrings("SDL_pixels.h", includes[1]); try testing.expectEqualStrings("SDL_rect.h", includes[2]); } test "flow: end-to-end with mock data" { const allocator = testing.allocator; // Primary header content (simplified SDL_gpu.h) const primary_source = \\typedef struct SDL_GPUDevice SDL_GPUDevice; \\extern void SDL_Func(SDL_GPUDevice *device, SDL_Window *window); ; // Parse primary var primary_scanner = patterns.Scanner.init(allocator, primary_source); const primary_decls = try primary_scanner.scan(); defer { for (primary_decls) |decl| { switch (decl) { .opaque_type => |o| { allocator.free(o.name); if (o.doc_comment) |doc| allocator.free(doc); }, .function_decl => |f| { allocator.free(f.name); allocator.free(f.return_type); if (f.doc_comment) |doc| allocator.free(doc); for (f.params) |p| { allocator.free(p.name); allocator.free(p.type_name); } allocator.free(f.params); }, else => {}, } } allocator.free(primary_decls); } // Analyze var resolver = dependency_resolver.DependencyResolver.init(allocator); defer resolver.deinit(); try resolver.analyze(primary_decls); const missing = try resolver.getMissingTypes(allocator); defer { for (missing) |m| allocator.free(m); allocator.free(missing); } // Verify we detected SDL_Window as missing var found_window = false; for (missing) |m| { if (std.mem.eql(u8, m, "SDL_Window")) { found_window = true; break; } } try testing.expect(found_window); }