Backlog/lib/sdl3/parser/test_flow.zig

148 lines
4.8 KiB
Zig

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 <SDL3/SDL_stdinc.h>
\\#include <SDL3/SDL_pixels.h>
\\
\\// Some code
\\#include <SDL3/SDL_rect.h>
\\#include <stdio.h> // 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);
}