# HG changeset patch # User Matthew Wild # Date 1739816663 0 # Node ID 48c056c10e5a6b9a73f76cb9eace22d82df41a65 # Parent 1465b1e305df7635beff6b61cfce0f9bccb08931 util.argparse: Add strict mode + tests diff -r 1465b1e305df -r 48c056c10e5a spec/util_argparse_spec.lua --- a/spec/util_argparse_spec.lua Mon Feb 17 17:02:35 2025 +0000 +++ b/spec/util_argparse_spec.lua Mon Feb 17 18:24:23 2025 +0000 @@ -24,10 +24,28 @@ assert.same({ "bar"; "--baz" }, arg); end); + it("allows continuation beyond first positional argument", function() + local arg = { "--foo"; "bar"; "--baz" }; + local opts, err = parse(arg, { stop_on_positional = false }); + assert.falsy(err); + assert.same({ foo = true, baz = true, "bar" }, opts); + -- All input should have been consumed: + assert.same({ }, arg); + end); + it("expands short options", function() - local opts, err = parse({ "--foo"; "-b" }, { short_params = { b = "bar" } }); - assert.falsy(err); - assert.same({ foo = true; bar = true }, opts); + do + local opts, err = parse({ "--foo"; "-b" }, { short_params = { b = "bar" } }); + assert.falsy(err); + assert.same({ foo = true; bar = true }, opts); + end + + do + -- Same test with strict mode enabled and all parameters declared + local opts, err = parse({ "--foo"; "-b" }, { kv_params = { foo = true, bar = true }; short_params = { b = "bar" }, strict = true }); + assert.falsy(err); + assert.same({ foo = true; bar = true }, opts); + end end); it("supports value arguments", function() @@ -51,8 +69,30 @@ end); it("supports array arguments", function () - local opts, err = parse({ "--item"; "foo"; "--item"; "bar" }, { array_params = { item = true } }); + do + local opts, err = parse({ "--item"; "foo"; "--item"; "bar" }, { array_params = { item = true } }); + assert.falsy(err); + assert.same({"foo","bar"}, opts.item); + end + + do + -- Same test with strict mode enabled + local opts, err = parse({ "--item"; "foo"; "--item"; "bar" }, { array_params = { item = true }, strict = true }); + assert.falsy(err); + assert.same({"foo","bar"}, opts.item); + end + end) + + it("rejects unknown parameters in strict mode", function () + local opts, err, err2 = parse({ "--item"; "foo"; "--item"; "bar", "--foobar" }, { array_params = { item = true }, strict = true }); + assert.falsy(opts); + assert.same("param-not-found", err); + assert.same("--foobar", err2); + end); + + it("accepts known kv parameters in strict mode", function () + local opts, err = parse({ "--item=foo" }, { kv_params = { item = true }, strict = true }); assert.falsy(err); - assert.same({"foo","bar"}, opts.item); - end) + assert.same("foo", opts.item); + end); end); diff -r 1465b1e305df -r 48c056c10e5a util/argparse.lua --- a/util/argparse.lua Mon Feb 17 17:02:35 2025 +0000 +++ b/util/argparse.lua Mon Feb 17 18:24:23 2025 +0000 @@ -2,6 +2,8 @@ local short_params = config and config.short_params or {}; local value_params = config and config.value_params or {}; local array_params = config and config.array_params or {}; + local kv_params = config and config.kv_params or {}; + local strict = config and config.strict; local stop_on_positional = not config or config.stop_on_positional ~= false; local parsed_opts = {}; @@ -33,9 +35,11 @@ return nil, "param-not-found", raw_param; end + local uparam = param:match("^[^=]*"):gsub("%-", "_"); + local param_k, param_v; - if value_params[param] or array_params[param] then - param_k, param_v = param, table.remove(arg, 1); + if value_params[uparam] or array_params[uparam] then + param_k, param_v = uparam, table.remove(arg, 1); if not param_v then return nil, "missing-value", raw_param; end @@ -49,8 +53,11 @@ end end param_k = param_k:gsub("%-", "_"); + if strict and not kv_params[param_k] then + return nil, "param-not-found", raw_param; + end end - if array_params[param] then + if array_params[uparam] then if parsed_opts[param_k] then table.insert(parsed_opts[param_k], param_v); else