359 lines
12 KiB
Zig
359 lines
12 KiB
Zig
const std = @import("std");
|
|
const parsing = @import("parsing");
|
|
const ArgumentRegistry = @import("ArgumentRegistry").ArgumentRegistry;
|
|
const metadata = @import("metadata");
|
|
const ArgumentType = @import("ArgumentType").ArgumentType;
|
|
|
|
// Test struct for parsing
|
|
const SimpleConfig = struct {
|
|
verbose: bool = false,
|
|
output: []const u8 = "default.txt",
|
|
count: u32 = 10,
|
|
|
|
pub const meta = .{
|
|
.verbose = .{ .short = 'v', .help = "Verbose output" },
|
|
.output = .{ .short = 'o', .help = "Output file" },
|
|
.count = .{ .short = 'c', .help = "Item count" },
|
|
};
|
|
};
|
|
|
|
test "parse long boolean flag" {
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(SimpleConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "--verbose" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const value = registry.getParsedValue("verbose");
|
|
try std.testing.expect(value != null);
|
|
try std.testing.expectEqual(true, value.?.bool);
|
|
}
|
|
|
|
test "parse short boolean flag" {
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(SimpleConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "-v" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const value = registry.getParsedValue("verbose");
|
|
try std.testing.expect(value != null);
|
|
try std.testing.expectEqual(true, value.?.bool);
|
|
}
|
|
|
|
test "parse long flag with equals value" {
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(SimpleConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "--output=myfile.txt" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const value = registry.getParsedValue("output");
|
|
try std.testing.expect(value != null);
|
|
try std.testing.expectEqualStrings("myfile.txt", value.?.string);
|
|
}
|
|
|
|
test "parse long flag with space-separated value" {
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(SimpleConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "--output", "myfile.txt" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const value = registry.getParsedValue("output");
|
|
try std.testing.expect(value != null);
|
|
try std.testing.expectEqualStrings("myfile.txt", value.?.string);
|
|
}
|
|
|
|
test "parse short flag with value" {
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(SimpleConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "-o", "myfile.txt" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const value = registry.getParsedValue("output");
|
|
try std.testing.expect(value != null);
|
|
try std.testing.expectEqualStrings("myfile.txt", value.?.string);
|
|
}
|
|
|
|
test "parse integer value" {
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(SimpleConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "--count=42" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const value = registry.getParsedValue("count");
|
|
try std.testing.expect(value != null);
|
|
try std.testing.expectEqual(@as(u32, 42), value.?.u32);
|
|
}
|
|
|
|
test "parse multiple arguments" {
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(SimpleConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "-v", "--output", "test.txt", "--count=99" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const verbose = registry.getParsedValue("verbose");
|
|
const output = registry.getParsedValue("output");
|
|
const count = registry.getParsedValue("count");
|
|
|
|
try std.testing.expect(verbose != null);
|
|
try std.testing.expectEqual(true, verbose.?.bool);
|
|
|
|
try std.testing.expect(output != null);
|
|
try std.testing.expectEqualStrings("test.txt", output.?.string);
|
|
|
|
try std.testing.expect(count != null);
|
|
try std.testing.expectEqual(@as(u32, 99), count.?.u32);
|
|
}
|
|
|
|
test "parse multi-flag short form" {
|
|
const MultiFlag = struct {
|
|
verbose: bool = false,
|
|
debug: bool = false,
|
|
quiet: bool = false,
|
|
|
|
pub const meta = .{
|
|
.verbose = .{ .short = 'v' },
|
|
.debug = .{ .short = 'd' },
|
|
.quiet = .{ .short = 'q' },
|
|
};
|
|
};
|
|
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(MultiFlag, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "-vdq" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const verbose = registry.getParsedValue("verbose");
|
|
const debug = registry.getParsedValue("debug");
|
|
const quiet = registry.getParsedValue("quiet");
|
|
|
|
try std.testing.expect(verbose != null);
|
|
try std.testing.expectEqual(true, verbose.?.bool);
|
|
try std.testing.expect(debug != null);
|
|
try std.testing.expectEqual(true, debug.?.bool);
|
|
try std.testing.expect(quiet != null);
|
|
try std.testing.expectEqual(true, quiet.?.bool);
|
|
}
|
|
|
|
test "parse help flag" {
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(SimpleConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "--help" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
try std.testing.expect(registry.isHelpRequested());
|
|
}
|
|
|
|
test "parse short help flag" {
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(SimpleConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "-h" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
try std.testing.expect(registry.isHelpRequested());
|
|
}
|
|
|
|
test "unknown argument error" {
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(SimpleConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "--unknown" };
|
|
const result = parsing.parseArgv(®istry, argv);
|
|
|
|
try std.testing.expectError(error.UnknownArgument, result);
|
|
}
|
|
|
|
test "missing value error" {
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(SimpleConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "--output" };
|
|
const result = parsing.parseArgv(®istry, argv);
|
|
|
|
try std.testing.expectError(error.MissingArgumentValue, result);
|
|
}
|
|
|
|
test "populate struct with defaults" {
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(SimpleConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{"program"};
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const config = try parsing.populateStruct(SimpleConfig, ®istry, std.testing.allocator);
|
|
|
|
try std.testing.expectEqual(false, config.verbose);
|
|
try std.testing.expectEqualStrings("default.txt", config.output);
|
|
try std.testing.expectEqual(@as(u32, 10), config.count);
|
|
}
|
|
|
|
test "populate struct with parsed values" {
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(SimpleConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "-v", "--output=result.txt", "--count=5" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const config = try parsing.populateStruct(SimpleConfig, ®istry, std.testing.allocator);
|
|
|
|
try std.testing.expectEqual(true, config.verbose);
|
|
try std.testing.expectEqualStrings("result.txt", config.output);
|
|
try std.testing.expectEqual(@as(u32, 5), config.count);
|
|
}
|
|
|
|
test "populate struct with mixed defaults and values" {
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(SimpleConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "-v" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const config = try parsing.populateStruct(SimpleConfig, ®istry, std.testing.allocator);
|
|
|
|
try std.testing.expectEqual(true, config.verbose);
|
|
try std.testing.expectEqualStrings("default.txt", config.output);
|
|
try std.testing.expectEqual(@as(u32, 10), config.count);
|
|
}
|
|
|
|
test "parse enum values" {
|
|
const Mode = enum { fast, slow, medium };
|
|
|
|
const EnumConfig = struct {
|
|
mode: Mode = .medium,
|
|
|
|
pub const meta = .{
|
|
.mode = .{ .help = "Processing mode" },
|
|
};
|
|
};
|
|
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(EnumConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "--mode=fast" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const config = try parsing.populateStruct(EnumConfig, ®istry, std.testing.allocator);
|
|
|
|
try std.testing.expectEqual(Mode.fast, config.mode);
|
|
}
|
|
|
|
test "parse optional types" {
|
|
const OptionalConfig = struct {
|
|
name: ?[]const u8 = null,
|
|
age: ?u32 = null,
|
|
|
|
pub const meta = .{
|
|
.name = .{ .help = "Optional name" },
|
|
.age = .{ .help = "Optional age" },
|
|
};
|
|
};
|
|
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(OptionalConfig, "test");
|
|
|
|
// Test with values
|
|
{
|
|
const argv = &[_][:0]const u8{ "program", "--name=Alice", "--age=30" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const config = try parsing.populateStruct(OptionalConfig, ®istry, std.testing.allocator);
|
|
|
|
try std.testing.expect(config.name != null);
|
|
try std.testing.expectEqualStrings("Alice", config.name.?);
|
|
try std.testing.expect(config.age != null);
|
|
try std.testing.expectEqual(@as(u32, 30), config.age.?);
|
|
}
|
|
}
|
|
|
|
test "parse string list with comma separation" {
|
|
const ListConfig = struct {
|
|
files: []const []const u8 = &[_][]const u8{},
|
|
|
|
pub const meta = .{
|
|
.files = .{ .help = "List of files" },
|
|
};
|
|
};
|
|
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(ListConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "--files=a.txt,b.txt,c.txt" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const value = registry.getParsedValue("files");
|
|
try std.testing.expect(value != null);
|
|
try std.testing.expectEqual(@as(usize, 3), value.?.string_list.len);
|
|
try std.testing.expectEqualStrings("a.txt", value.?.string_list[0]);
|
|
try std.testing.expectEqualStrings("b.txt", value.?.string_list[1]);
|
|
try std.testing.expectEqualStrings("c.txt", value.?.string_list[2]);
|
|
}
|
|
|
|
test "parse string list with repeated arguments" {
|
|
const ListConfig = struct {
|
|
files: []const []const u8 = &[_][]const u8{},
|
|
|
|
pub const meta = .{
|
|
.files = .{ .help = "List of files" },
|
|
};
|
|
};
|
|
|
|
var registry = ArgumentRegistry.init(std.testing.allocator);
|
|
defer registry.deinit();
|
|
|
|
try registry.registerMetadata(ListConfig, "test");
|
|
|
|
const argv = &[_][:0]const u8{ "program", "--files=a.txt", "--files=b.txt", "--files=c.txt" };
|
|
try parsing.parseArgv(®istry, argv);
|
|
|
|
const value = registry.getParsedValue("files");
|
|
try std.testing.expect(value != null);
|
|
try std.testing.expectEqual(@as(usize, 3), value.?.string_list.len);
|
|
try std.testing.expectEqualStrings("a.txt", value.?.string_list[0]);
|
|
try std.testing.expectEqualStrings("b.txt", value.?.string_list[1]);
|
|
try std.testing.expectEqualStrings("c.txt", value.?.string_list[2]);
|
|
}
|