Skip to content

Commit

Permalink
wip - almost total re-write
Browse files Browse the repository at this point in the history
  • Loading branch information
Henrik Larsson committed Oct 5, 2024
1 parent ab3df47 commit 841e728
Show file tree
Hide file tree
Showing 30 changed files with 786 additions and 266 deletions.
83 changes: 38 additions & 45 deletions Simple.ArgumentParser.Example/Program.cs
Original file line number Diff line number Diff line change
@@ -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;
79 changes: 79 additions & 0 deletions Simple.ArgumentParser.Tests/ArgumentParserTests.cs
Original file line number Diff line number Diff line change
@@ -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"));
}
}
33 changes: 33 additions & 0 deletions Simple.ArgumentParser.Tests/Options/AlphaOptionTests.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
78 changes: 78 additions & 0 deletions Simple.ArgumentParser.Tests/Options/BooleanOptionTests.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,8 @@
<Using Include="Xunit"/>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Simple.ArgumentParser\Simple.ArgumentParser.csproj" />
</ItemGroup>

</Project>
9 changes: 0 additions & 9 deletions Simple.ArgumentParser.Tests/UnitTest1.cs

This file was deleted.

34 changes: 34 additions & 0 deletions Simple.ArgumentParser/Args.cs
Original file line number Diff line number Diff line change
@@ -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<Command> Valid { get; set; } = [];
public List<Command> Ignored { get; } = [];
public List<string> Missing { get; } = [];
public List<string> 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<Command> GetAll() => Valid;
}
8 changes: 8 additions & 0 deletions Simple.ArgumentParser/ArgumentOptionException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Simple.ArgumentParser;

public class ArgumentOptionException : Exception
{
public ArgumentOptionException(string message) : base(message)
{
}
}
Loading

0 comments on commit 841e728

Please sign in to comment.