diff --git a/Simple.ArgumentParser.Example/Program.cs b/Simple.ArgumentParser.Example/Program.cs
index eb4bb20..63acfec 100644
--- a/Simple.ArgumentParser.Example/Program.cs
+++ b/Simple.ArgumentParser.Example/Program.cs
@@ -1,74 +1,67 @@
using Simple.ArgumentParser;
-using Type = Simple.ArgumentParser.Type;
-args = ["--key", "just", "a", "key", "--bool", "true", "--number", "42"];
+//args = ["-t", "hejsan", "-n", "3.1", "-b", "true", "-f", "-fl", "1.3" ];
-var arguments = new Parser()
- .Options
- .Add(name: "key",
- shortName: "k",
- description: "An alphanumeric value",
- type: Type.Alpha,
- required: true)
- .Add(name: "flag",
- shortName: "f",
- description: "Just a simple flag",
- type: Type.None,
+var arguments = new ArgumentParser()
+ .AddAlphaOption(name: "name",
+ shortName: 'n',
+ description: "Your full name",
required: false)
- .Add(name: "bool",
- shortName: "b",
- description: "A boolean value (true/false)",
- type: Type.Boolean,
- required: true)
- .Add(name: "a-super-long-option",
- shortName: "l",
- description: "This is a really long option",
- type: Type.Alpha,
+ .AddIntegerOption(name: "age",
+ shortName: 'a',
+ description: "Your age",
required: false)
- .Add(name: "number",
- shortName: "n",
- description: "An integer value",
- type: Type.Integer,
- required: true)
- .AddHelp()
- .AddVersion()
- .AddDescription("A description of the application.")
- .Build()
+ .AddEnumerateOption(name: "sex",
+ shortName: 's',
+ description: "Enter your sex (male/female/idiot)",
+ ["male", "female", "idiot"],
+ required: false)
+ .AddBooleanOption(name: "happy",
+ shortName: 'H',
+ description: "If you are happy or not",
+ required: false)
+ .AddHelpOption("A description of the application.")
+ .AddVersionOption("1.2.3-alpha")
.Parse(args);
-
// handle help command
-if (arguments.ShowHelpRequested)
+if (arguments.HelpRequested)
{
Console.WriteLine(arguments.HelpSection);
return 1;
}
// handle version command
-if (arguments.ShowVersionRequested)
+if (arguments.VersionRequested)
{
Console.WriteLine(arguments.Version);
return 2;
}
// handle invalid commands
-if (arguments.InvalidCommands.Count > 0)
+if (arguments.HasInvalidCommands)
{
- arguments.InvalidCommands.ForEach(Console.WriteLine);
- return -2;
+ arguments.Invalid.ForEach(Console.WriteLine);
}
// handle missing commands
-if (arguments.MissingCommands.Count > 0)
+if (arguments.HasMissingCommands)
+{
+ arguments.Missing.ForEach(Console.WriteLine);
+}
+
+// handle ignored commands
+if (arguments.HasIgnoredCommands)
{
- arguments.MissingCommands.ForEach(c => Console.WriteLine($"Required command is missing: {c}"));
- return -1;
+ Console.WriteLine("Ignored commands:");
+ arguments.Ignored.ForEach(c => Console.WriteLine($"Name: {c.Name}, Type: {c.OptionType}, Value: {c.Value}"));
}
-arguments.ValidCommands.ForEach(c => Console.WriteLine($"Name: {c.Name}, Type: {c.Type}, Value: {c.Value}"));
+// handle valid commands
+if (arguments.IsValid && arguments.Any())
+{
+ Console.WriteLine("Valid commands:");
+ arguments.GetAll().ForEach(c => Console.WriteLine($"Name: {c.Name}, Type: {c.OptionType}, Value: {c.Value}"));
+}
-Console.WriteLine($"Hello, {arguments.ValidCommands.Single(c => c.Name == "name").Value}! You look " +
- $"a lot older than {arguments.ValidCommands.Single(c => c.Name == "age").Value}. " +
- $"Also, you are {(arguments.ValidCommands.Single(c => c.Name == "is-cool").Value == "true" ? "very" : "not very")} cool.");
-Console.WriteLine($"Flag: {arguments.ValidCommands.Any(c => c.Name == "just-a-flag")}");
return 0;
\ No newline at end of file
diff --git a/Simple.ArgumentParser.Tests/ArgumentParserTests.cs b/Simple.ArgumentParser.Tests/ArgumentParserTests.cs
new file mode 100644
index 0000000..8649022
--- /dev/null
+++ b/Simple.ArgumentParser.Tests/ArgumentParserTests.cs
@@ -0,0 +1,79 @@
+namespace Simple.ArgumentParser.Tests;
+
+public class ArgumentParserTests
+{
+ [Fact]
+ public void Parse_should_handle_expected_arguments()
+ {
+ // arrange
+
+ string[] args = [
+ "--alpha", "value",
+ "--boolean", "true",
+ "--char", "c",
+ "--double", "3.14",
+ "--enumerate", "a",
+ "--flag",
+ "--integer", "42",
+ "--help",
+ "--version"
+ ];
+
+ var subjectUnderTest = new ArgumentParser()
+ .AddAlphaOption("alpha", 'a', "description")
+ .AddBooleanOption("boolean", 'b', "description")
+ .AddCharOption("char", 'c', "description")
+ .AddDoubleOption("double", 'd', "description")
+ .AddEnumerateOption("enumerate", 'e', "description", ["a", "b", "c"])
+ .AddFlagOption("flag", 'f', "description")
+ .AddIntegerOption("integer", 'i', "description")
+ .AddVersionOption()
+ .AddHelpOption();
+
+ // act
+
+ var result = subjectUnderTest.Parse(args);
+
+ // assert
+
+ Assert.NotNull(result);
+ Assert.True(result.HelpRequested);
+ Assert.True(result.VersionRequested);
+ Assert.True(result.IsValid);
+ Assert.False(result.HasMissingCommands);
+ Assert.False(result.HasIgnoredCommands);
+ Assert.False(result.HasInvalidCommands);
+ Assert.NotNull(result.Version);
+ Assert.NotEmpty(result.Version);
+ Assert.NotNull(result.HelpSection);
+ Assert.NotEmpty(result.HelpSection);
+ Assert.NotNull(result.Get("alpha"));
+ }
+
+ [Fact]
+ public void Parse_should_ignore_unexpected_arguments()
+ {
+ // arrange
+
+ var args = new[] { "--help" };
+
+ var subjectUnderTest = new ArgumentParser();
+
+ // act
+
+ var result = subjectUnderTest.Parse(args);
+
+ // assert
+
+ Assert.NotNull(result);
+ Assert.False(result.HelpRequested);
+ Assert.False(result.VersionRequested);
+ Assert.True(result.IsValid);
+ Assert.False(result.HasMissingCommands);
+ Assert.True(result.HasIgnoredCommands);
+ Assert.False(result.HasInvalidCommands);
+ Assert.Null(result.Version);
+ Assert.Null(result.HelpSection);
+ Assert.Null(result.Get("help"));
+ }
+}
\ No newline at end of file
diff --git a/Simple.ArgumentParser.Tests/Options/AlphaOptionTests.cs b/Simple.ArgumentParser.Tests/Options/AlphaOptionTests.cs
new file mode 100644
index 0000000..a697a35
--- /dev/null
+++ b/Simple.ArgumentParser.Tests/Options/AlphaOptionTests.cs
@@ -0,0 +1,33 @@
+using Simple.ArgumentParser.Options;
+
+namespace Simple.ArgumentParser.Tests.Options;
+
+public class AlphaOptionTests
+{
+ private static AlphaOption GetSubjectUnderTest(OptionSettings? settings = null) => new (
+ name: "test-name",
+ shortName: 't',
+ description: "test-description",
+ settings: settings ?? new OptionSettings());
+
+ [Theory]
+ [InlineData("alpha")]
+ [InlineData("123")]
+ [InlineData("true")]
+ [InlineData(" ")]
+ public void ValueIsValid_should_return_true(string inlineData)
+ {
+ // arrange
+
+ var subjectUnderTest = GetSubjectUnderTest();
+
+ // act
+
+ var result = subjectUnderTest.ValueIsValid(inlineData, out var message);
+
+ // assert
+
+ Assert.True(result);
+ Assert.Empty(message);
+ }
+}
\ No newline at end of file
diff --git a/Simple.ArgumentParser.Tests/Options/BooleanOptionTests.cs b/Simple.ArgumentParser.Tests/Options/BooleanOptionTests.cs
new file mode 100644
index 0000000..bed1863
--- /dev/null
+++ b/Simple.ArgumentParser.Tests/Options/BooleanOptionTests.cs
@@ -0,0 +1,78 @@
+using Simple.ArgumentParser.Options;
+
+namespace Simple.ArgumentParser.Tests.Options;
+
+public class BooleanOptionTests
+{
+ private static BooleanOption GetSubjectUnderTest(OptionSettings? settings = null) => new(
+ name: "test-name",
+ shortName: 't',
+ description: "test-description",
+ settings: settings ?? new OptionSettings());
+
+ private static OptionSettings GetStrictSettings() => new OptionSettings
+ {
+ Strict = true,
+ Required = false
+ };
+
+ [Theory]
+ [InlineData("true")]
+ [InlineData("false")]
+ [InlineData("1")]
+ [InlineData("0")]
+ public void ValueIsValid_should_return_true_with_strict_off(string inlineData)
+ {
+ // arrange
+
+ var subjectUnderTest = GetSubjectUnderTest();
+
+ // act
+
+ var result = subjectUnderTest.ValueIsValid(inlineData, out var message);
+
+ // assert
+
+ Assert.True(result);
+ Assert.Empty(message);
+ }
+
+ [Theory]
+ [InlineData("1")]
+ [InlineData("0")]
+ public void ValueIsValid_should_return_false_with_strict_on(string inlineData)
+ {
+ // arrange
+
+ var subjectUnderTest = GetSubjectUnderTest(GetStrictSettings());
+
+ // act
+
+ var result = subjectUnderTest.ValueIsValid(inlineData, out var message);
+
+ // assert
+
+ Assert.False(result);
+ Assert.NotEmpty(message);
+ }
+
+ [Theory]
+ [InlineData("-1")]
+ [InlineData("-0")]
+ [InlineData("text")]
+ public void ValueIsValid_should_return_false_with_strict_off(string inlineData)
+ {
+ // arrange
+
+ var subjectUnderTest = GetSubjectUnderTest();
+
+ // act
+
+ var result = subjectUnderTest.ValueIsValid(inlineData, out var message);
+
+ // assert
+
+ Assert.False(result);
+ Assert.NotEmpty(message);
+ }
+}
\ No newline at end of file
diff --git a/Simple.ArgumentParser.Tests/Simple.ArgumentParser.Tests.csproj b/Simple.ArgumentParser.Tests/Simple.ArgumentParser.Tests.csproj
index 085bddd..906c421 100644
--- a/Simple.ArgumentParser.Tests/Simple.ArgumentParser.Tests.csproj
+++ b/Simple.ArgumentParser.Tests/Simple.ArgumentParser.Tests.csproj
@@ -20,4 +20,8 @@
+
+
+
+
diff --git a/Simple.ArgumentParser.Tests/UnitTest1.cs b/Simple.ArgumentParser.Tests/UnitTest1.cs
deleted file mode 100644
index 14f084d..0000000
--- a/Simple.ArgumentParser.Tests/UnitTest1.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Simple.ArgumentParser.Tests;
-
-public class UnitTest1
-{
- [Fact]
- public void Test1()
- {
- }
-}
\ No newline at end of file
diff --git a/Simple.ArgumentParser/Args.cs b/Simple.ArgumentParser/Args.cs
new file mode 100644
index 0000000..f875945
--- /dev/null
+++ b/Simple.ArgumentParser/Args.cs
@@ -0,0 +1,34 @@
+namespace Simple.ArgumentParser;
+
+public class Args
+{
+ public bool IsValid => !(HasInvalidCommands || HasMissingCommands);
+ public bool HasIgnoredCommands => Ignored.Count > 0;
+ public bool HasMissingCommands => Missing.Count > 0;
+ public bool HasInvalidCommands => Invalid.Count > 0;
+ public bool HelpRequested { get; internal set; }
+ public bool VersionRequested { get; internal set; }
+
+
+ public List Valid { get; set; } = [];
+ public List Ignored { get; } = [];
+ public List Missing { get; } = [];
+ public List Invalid { get; } = [];
+ public string? HelpSection { get; internal set; }
+ public string? Version { get; internal set; }
+
+
+ internal Args()
+ {
+ }
+
+
+ public bool Any() => Valid.Count > 0;
+
+ public Command? Get(string key)
+ {
+ return Valid.SingleOrDefault(c => c.Name == key);
+ }
+
+ public List GetAll() => Valid;
+}
\ No newline at end of file
diff --git a/Simple.ArgumentParser/ArgumentOptionException.cs b/Simple.ArgumentParser/ArgumentOptionException.cs
new file mode 100644
index 0000000..efb6500
--- /dev/null
+++ b/Simple.ArgumentParser/ArgumentOptionException.cs
@@ -0,0 +1,8 @@
+namespace Simple.ArgumentParser;
+
+public class ArgumentOptionException : Exception
+{
+ public ArgumentOptionException(string message) : base(message)
+ {
+ }
+}
\ No newline at end of file
diff --git a/Simple.ArgumentParser/ArgumentParser.cs b/Simple.ArgumentParser/ArgumentParser.cs
new file mode 100644
index 0000000..5411adc
--- /dev/null
+++ b/Simple.ArgumentParser/ArgumentParser.cs
@@ -0,0 +1,211 @@
+using System.Reflection;
+using System.Text.RegularExpressions;
+using Simple.ArgumentParser.Builders;
+using Simple.ArgumentParser.Options;
+
+namespace Simple.ArgumentParser;
+
+public class ArgumentParser
+{
+ private readonly bool _strictMode;
+ private readonly List