Changeset

13733:48c056c10e5a 13.0

util.argparse: Add strict mode + tests
author Matthew Wild <mwild1@gmail.com>
date Mon, 17 Feb 2025 18:24:23 +0000
parents 13732:1465b1e305df
children 13734:c133635d0bc6
files spec/util_argparse_spec.lua util/argparse.lua
diffstat 2 files changed, 56 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- 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);
--- 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