From 74029edae0e1574d3d371a3cff829268d8952cf0 Mon Sep 17 00:00:00 2001 From: mpeterv Date: Mon, 30 Dec 2013 23:42:00 +0400 Subject: [PATCH] added some tests, fixed some wrong behaviours --- spec/arguments_spec.lua | 164 ++++++++++++++++++++++++++++++++++++++++ src/largparse.lua | 3 - src/state.lua | 28 +++++-- 3 files changed, 184 insertions(+), 11 deletions(-) create mode 100644 spec/arguments_spec.lua diff --git a/spec/arguments_spec.lua b/spec/arguments_spec.lua new file mode 100644 index 0000000..283bf11 --- /dev/null +++ b/spec/arguments_spec.lua @@ -0,0 +1,164 @@ +local largparse = require "largparse" + +describe("tests related to positional arguments", function() + local function curry(f, ...) + local args = {...} + return function() return f(table.unpack(args)) end + end + + describe("passing correct arguments", function() + it("handles empty parser correctly", function() + local parser = largparse.parser() + local args = parser:parse({}) + assert.same(args, {}) + end) + + it("handles one argument correctly", function() + local parser = largparse.parser() + parser:argument "foo" + local args = parser:parse({"bar"}) + assert.same(args, {foo = "bar"}) + end) + + it("handles several arguments correctly", function() + local parser = largparse.parser() + parser:argument "foo1" + parser:argument "foo2" + local args = parser:parse({"bar", "baz"}) + assert.same(args, {foo1 = "bar", foo2 = "baz"}) + end) + + it("handles multi-argument correctly", function() + local parser = largparse.parser() + parser:argument("foo", { + args = "*" + }) + local args = parser:parse({"bar", "baz", "qu"}) + assert.same(args, {foo = {"bar", "baz", "qu"}}) + end) + + it("handles restrained multi-argument correctly", function() + local parser = largparse.parser() + parser:argument("foo", { + args = "2-4" + }) + local args = parser:parse({"bar", "baz"}) + assert.same(args, {foo = {"bar", "baz"}}) + end) + + it("handles several multi-arguments correctly", function() + local parser = largparse.parser() + parser:argument("foo1", { + args = "1-2" + }) + parser:argument("foo2", { + args = "*" + }) + local args = parser:parse({"bar"}) + assert.same(args, {foo1 = {"bar"}, foo2 = {}}) + args = parser:parse({"bar", "baz", "qu"}) + assert.same(args, {foo1 = {"bar", "baz"}, foo2 = {"qu"}}) + end) + end) + + describe("passing incorrect arguments", function() + local old_parser = largparse.parser + + setup(function() + largparse.parser = old_parser:extends() + function largparse.parser:error(fmt, ...) + error(fmt:format(...)) + end + end) + + + it("handles extra arguments with empty parser correctly", function() + local parser = largparse.parser() + + assert.has_error(curry(parser.parse, parser, {"foo"}), "too many arguments") + end) + + it("handles extra arguments with one argument correctly", function() + local parser = largparse.parser() + parser:argument "foo" + + assert.has_error(curry(parser.parse, parser, {"bar", "baz"}), "too many arguments") + end) + + it("handles sudden option correctly", function() + local parser = largparse.parser() + parser:argument "foo" + + assert.has_error(curry(parser.parse, parser, {"-q"}), "unknown option -q") + end) + + it("handles too few arguments with one argument correctly", function() + local parser = largparse.parser() + parser:argument "foo" + + assert.has_error(curry(parser.parse, parser, {}), "too few arguments") + end) + + it("handles extra arguments with several arguments correctly", function() + local parser = largparse.parser() + parser:argument "foo1" + parser:argument "foo2" + + assert.has_error(curry(parser.parse, parser, {"bar", "baz", "qu"}), "too many arguments") + end) + + it("handles too few arguments with several arguments correctly", function() + local parser = largparse.parser() + parser:argument "foo1" + parser:argument "foo2" + + assert.has_error(curry(parser.parse, parser, {"bar"}), "too few arguments") + end) + + it("handles too few arguments with multi-argument correctly", function() + local parser = largparse.parser() + parser:argument("foo", { + args = "+" + }) + assert.has_error(curry(parser.parse, parser, {}), "too few arguments") + end) + + it("handles too many arguments with multi-argument correctly", function() + local parser = largparse.parser() + parser:argument("foo", { + args = "2-4" + }) + assert.has_error(curry(parser.parse, parser, {"foo", "bar", "baz", "qu", "quu"}), "too many arguments") + end) + + it("handles too few arguments with multi-argument correctly", function() + local parser = largparse.parser() + parser:argument("foo", { + args = "2-4" + }) + assert.has_error(curry(parser.parse, parser, {"foo"}), "too few arguments") + end) + + it("handles too many arguments with several multi-arguments correctly", function() + local parser = largparse.parser() + parser:argument("foo1", { + args = "1-2" + }) + parser:argument("foo2", { + args = "0-1" + }) + assert.has_error(curry(parser.parse, parser, {"foo", "bar", "baz", "qu"}), "too many arguments") + end) + + it("handles too few arguments with several multi-arguments correctly", function() + local parser = largparse.parser() + parser:argument("foo1", { + args = "1-2" + }) + parser:argument("foo2", { + args = "*" + }) + assert.has_error(curry(parser.parse, parser, {}), "too few arguments") + end) + end) +end) \ No newline at end of file diff --git a/src/largparse.lua b/src/largparse.lua index 1ea46b1..8b9a0d1 100644 --- a/src/largparse.lua +++ b/src/largparse.lua @@ -99,9 +99,6 @@ function Parser:argument(name, ...) element.mincount, element.maxcount = self:parse_boundaries(element.count) element.minargs, element.maxargs = self:parse_boundaries(element.args) - if element.minargs == 0 then - element.mincount = 0 - end table.insert(self.arguments, element) table.insert(self.elements, element) diff --git a/src/state.lua b/src/state.lua index 5a6ab9b..baa57d6 100644 --- a/src/state.lua +++ b/src/state.lua @@ -56,14 +56,16 @@ function State:get_result() invocations = self._result[element.target] if element.maxcount == 1 then - if #invocations > 0 then - if element.maxargs == 0 then + if element.maxargs == 0 then + if #invocations > 0 then result[element.target] = true - elseif element.maxargs == 1 and element.minargs == 1 then - result[element.target] = invocations[1][1] - else - result[element.target] = invocations[1] end + elseif element.maxargs == 1 and element.minargs == 1 then + if #invocations > 0 then + result[element.target] = invocations[1][1] + end + else + result[element.target] = invocations[1] or {} end else if element.maxargs == 0 then @@ -89,6 +91,11 @@ function State:_check() local invocations for _, element in ipairs(self._all_elements) do invocations = self._result[element.target] or {} + + if element.type == "argument" and #invocations == 0 then + invocations[1] = {} + end + if #invocations > element.maxcount then if element.no_overwrite then self:_error("option %s can only be used %d times", element.name, element.maxcount) @@ -104,8 +111,13 @@ function State:_check() self:_assert(#invocations >= element.mincount, "option %s must be used at least %d times", element.name, element.mincount) for _, passed in ipairs(invocations) do - self:_assert(#passed <= element.maxargs, "%s takes at most %d arguments", element.name, element.maxargs) - self:_assert(#passed >= element.minargs, "%s takes at least %d arguments", element.name, element.minargs) + if element.type == "option" then + self:_assert(#passed <= element.maxargs, "%s takes at most %d arguments", element.name, element.maxargs) + self:_assert(#passed >= element.minargs, "%s takes at least %d arguments", element.name, element.minargs) + else + self:_assert(#passed <= element.maxargs, "too many arguments") + self:_assert(#passed >= element.minargs, "too few arguments") + end end self._result[element.target] = invocations