PranitInitial commit439f83c3 months agoHistory
83 lines · 3.5 KB · Zig
RawDownload
const std = @import("std"); pub fn parseToolArgsObject(alloc: std.mem.Allocator, args_json: []const u8) !std.json.ObjectMap {    const parsed = try std.json.parseFromSlice(std.json.Value, alloc, args_json, .{});    // The returned object map is backed by the parse allocation; callers should    // use an arena or allocator lifetime that outlives all borrowed values.    if (parsed.value != .object) return error.InvalidToolArguments;    return parsed.value.object;} pub fn requiredStringArg(args: std.json.ObjectMap, key: []const u8) ![]const u8 {    const value = args.get(key) orelse return error.InvalidToolArguments;    if (value != .string) return error.InvalidToolArguments;    return value.string;} pub fn optionalStringArg(args: std.json.ObjectMap, key: []const u8) ?[]const u8 {    const value = args.get(key) orelse return null;    if (value != .string) return null;    return value.string;} pub fn optionalBoolArg(args: std.json.ObjectMap, key: []const u8) ?bool {    const value = args.get(key) orelse return null;    if (value != .bool) return null;    return value.bool;} pub fn optionalIntArg(args: std.json.ObjectMap, key: []const u8) ?i64 {    const value = args.get(key) orelse return null;    if (value != .integer) return null;    return value.integer;} test "parseToolArgsObject parses object roots" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const arena = arena_state.allocator();     const args = try parseToolArgsObject(arena, "{\"path\":\"src/main.zig\"}");     try std.testing.expectEqualStrings("src/main.zig", args.get("path").?.string);} test "parseToolArgsObject rejects non-object roots" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const arena = arena_state.allocator();     try std.testing.expectError(error.InvalidToolArguments, parseToolArgsObject(arena, "[]"));} test "requiredStringArg rejects missing and wrong-type values" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const arena = arena_state.allocator();     const args = try parseToolArgsObject(arena, "{\"path\":\"src/main.zig\",\"count\":3}");     try std.testing.expectEqualStrings("src/main.zig", try requiredStringArg(args, "path"));    try std.testing.expectError(error.InvalidToolArguments, requiredStringArg(args, "missing"));    try std.testing.expectError(error.InvalidToolArguments, requiredStringArg(args, "count"));} test "optional typed args return payloads only for matching tags" {    var arena_state = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena_state.deinit();    const arena = arena_state.allocator();     const args = try parseToolArgsObject(arena, "{\"name\":\"fx\",\"enabled\":true,\"count\":3,\"other\":1.25}");     try std.testing.expectEqualStrings("fx", optionalStringArg(args, "name").?);    try std.testing.expect(optionalStringArg(args, "missing") == null);    try std.testing.expect(optionalStringArg(args, "enabled") == null);     try std.testing.expectEqual(true, optionalBoolArg(args, "enabled").?);    try std.testing.expect(optionalBoolArg(args, "missing") == null);    try std.testing.expect(optionalBoolArg(args, "name") == null);     try std.testing.expectEqual(@as(i64, 3), optionalIntArg(args, "count").?);    try std.testing.expect(optionalIntArg(args, "missing") == null);    try std.testing.expect(optionalIntArg(args, "other") == null);}