Add currently unused Input type

This commit is contained in:
Matt Nadareski
2024-12-04 19:28:34 -05:00
parent 9fe815676f
commit d704cec97b
3 changed files with 1280 additions and 0 deletions

View File

@@ -24,6 +24,7 @@
- Use recommended Min/Max/TryParse
- Add tests around ProcessingTool
- Add BaseExecutionContext tests
- Add currently unused Input type
### 3.2.4 (2024-11-24)

View File

@@ -0,0 +1,526 @@
using Xunit;
namespace MPF.ExecutionContexts.Test
{
public class InputTests
{
#region ProcessAsFlag
[Theory]
// Invalid type
[InlineData(InputType.None, "flag", new string[] { "flag" }, 0, false)]
[InlineData(InputType.Boolean, "flag", new string[] { "flag" }, 0, false)]
[InlineData(InputType.Int8, "flag", new string[] { "flag" }, 0, false)]
[InlineData(InputType.UInt8, "flag", new string[] { "flag" }, 0, false)]
[InlineData(InputType.Int16, "flag", new string[] { "flag" }, 0, false)]
[InlineData(InputType.UInt16, "flag", new string[] { "flag" }, 0, false)]
[InlineData(InputType.Int32, "flag", new string[] { "flag" }, 0, false)]
[InlineData(InputType.UInt32, "flag", new string[] { "flag" }, 0, false)]
[InlineData(InputType.Int64, "flag", new string[] { "flag" }, 0, false)]
[InlineData(InputType.UInt64, "flag", new string[] { "flag" }, 0, false)]
[InlineData(InputType.String, "flag", new string[] { "flag" }, 0, false)]
// Invalid parts
[InlineData(InputType.Flag, "flag", new string[0], 0, false)]
// Invalid index
[InlineData(InputType.Flag, "flag", new string[] { "flag" }, -1, false)]
[InlineData(InputType.Flag, "flag", new string[] { "flag" }, 1, false)]
// Invalid name
[InlineData(InputType.Flag, "flag", new string[] { "" }, 0, false)]
[InlineData(InputType.Flag, "flag", new string[] { "flag2" }, 0, false)]
// Valid
[InlineData(InputType.Flag, "flag", new string[] { "flag" }, 0, true)]
public void ProcessAsFlagTest(InputType type, string name, string[] parts, int index, bool expected)
{
Input input = new Input(type, name);
bool actual = input.ProcessAsFlag(parts, ref index);
Assert.Equal(expected, actual);
}
#endregion
#region ProcessAsBoolean
[Theory]
// Invalid type
[InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
// Invalid parts
[InlineData(InputType.Boolean, "flag", true, new string[0], 0, null)]
// Invalid index
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, -1, null)]
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 1, null)]
// Invalid name
[InlineData(InputType.Boolean, "flag", true, new string[] { "" }, 0, null)]
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag2" }, 0, null)]
// Valid name, no following
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Boolean, "flag", false, new string[] { "flag" }, 0, true)]
// Valid name, invalid following
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
[InlineData(InputType.Boolean, "flag", false, new string[] { "flag", "invalid" }, 0, true)]
// Valid name, valid following
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag", "true" }, 0, true)]
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag", "false" }, 0, false)]
public void ProcessAsBooleanTest(InputType type, string name, bool required, string[] parts, int index, bool? expected)
{
Input input = new Input(type, name, required);
bool? actual = input.ProcessAsBoolean(parts, ref index);
Assert.Equal(expected, actual);
}
#endregion
#region ProcessAsInt8
[Theory]
// Invalid type
[InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
// Invalid parts
[InlineData(InputType.Int8, "flag", true, new string[0], 0, null)]
// Invalid index
[InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, -1, null)]
[InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 1, null)]
// Invalid name
[InlineData(InputType.Int8, "flag", true, new string[] { "" }, 0, null)]
[InlineData(InputType.Int8, "flag", true, new string[] { "flag2" }, 0, null)]
// Valid name, no following
[InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int8, "flag", false, new string[] { "flag" }, 0, sbyte.MinValue)]
// Valid name, invalid following
[InlineData(InputType.Int8, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
[InlineData(InputType.Int8, "flag", false, new string[] { "flag", "invalid" }, 0, sbyte.MinValue)]
// Valid name, valid following
[InlineData(InputType.Int8, "flag", true, new string[] { "flag", "1" }, 0, (sbyte)1)]
[InlineData(InputType.Int8, "flag", true, new string[] { "flag", "-1" }, 0, (sbyte)-1)]
public void ProcessAsInt8Test(InputType type, string name, bool required, string[] parts, int index, sbyte? expected)
{
Input input = new Input(type, name, required);
sbyte? actual = input.ProcessAsInt8(parts, ref index);
Assert.Equal(expected, actual);
}
#endregion
#region ProcessAsUInt8
[Theory]
// Invalid type
[InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
// Invalid parts
[InlineData(InputType.UInt8, "flag", true, new string[0], 0, null)]
// Invalid index
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, -1, null)]
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 1, null)]
// Invalid name
[InlineData(InputType.UInt8, "flag", true, new string[] { "" }, 0, null)]
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag2" }, 0, null)]
// Valid name, no following
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt8, "flag", false, new string[] { "flag" }, 0, byte.MinValue)]
// Valid name, invalid following
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
[InlineData(InputType.UInt8, "flag", false, new string[] { "flag", "invalid" }, 0, byte.MinValue)]
// Valid name, valid following
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag", "1" }, 0, (byte)1)]
public void ProcessAsUInt8Test(InputType type, string name, bool required, string[] parts, int index, byte? expected)
{
Input input = new Input(type, name, required);
byte? actual = input.ProcessAsUInt8(parts, ref index);
Assert.Equal(expected, actual);
}
#endregion
#region ProcessAsInt16
[Theory]
// Invalid type
[InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
// Invalid parts
[InlineData(InputType.Int16, "flag", true, new string[0], 0, null)]
// Invalid index
[InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, -1, null)]
[InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 1, null)]
// Invalid name
[InlineData(InputType.Int16, "flag", true, new string[] { "" }, 0, null)]
[InlineData(InputType.Int16, "flag", true, new string[] { "flag2" }, 0, null)]
// Valid name, no following
[InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int16, "flag", false, new string[] { "flag" }, 0, short.MinValue)]
// Valid name, invalid following
[InlineData(InputType.Int16, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
[InlineData(InputType.Int16, "flag", false, new string[] { "flag", "invalid" }, 0, short.MinValue)]
// Valid name, valid following
[InlineData(InputType.Int16, "flag", true, new string[] { "flag", "1" }, 0, (short)1)]
[InlineData(InputType.Int16, "flag", true, new string[] { "flag", "-1" }, 0, (short)-1)]
public void ProcessAsInt16Test(InputType type, string name, bool required, string[] parts, int index, short? expected)
{
Input input = new Input(type, name, required);
short? actual = input.ProcessAsInt16(parts, ref index);
Assert.Equal(expected, actual);
}
#endregion
#region ProcessAsUInt16
[Theory]
// Invalid type
[InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
// Invalid parts
[InlineData(InputType.UInt16, "flag", true, new string[0], 0, null)]
// Invalid index
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, -1, null)]
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 1, null)]
// Invalid name
[InlineData(InputType.UInt16, "flag", true, new string[] { "" }, 0, null)]
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag2" }, 0, null)]
// Valid name, no following
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt16, "flag", false, new string[] { "flag" }, 0, ushort.MinValue)]
// Valid name, invalid following
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
[InlineData(InputType.UInt16, "flag", false, new string[] { "flag", "invalid" }, 0, ushort.MinValue)]
// Valid name, valid following
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag", "1" }, 0, (ushort)1)]
public void ProcessAsUInt16Test(InputType type, string name, bool required, string[] parts, int index, ushort? expected)
{
Input input = new Input(type, name, required);
ushort? actual = input.ProcessAsUInt16(parts, ref index);
Assert.Equal(expected, actual);
}
#endregion
#region ProcessAsInt32
[Theory]
// Invalid type
[InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
// Invalid parts
[InlineData(InputType.Int32, "flag", true, new string[0], 0, null)]
// Invalid index
[InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, -1, null)]
[InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 1, null)]
// Invalid name
[InlineData(InputType.Int32, "flag", true, new string[] { "" }, 0, null)]
[InlineData(InputType.Int32, "flag", true, new string[] { "flag2" }, 0, null)]
// Valid name, no following
[InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int32, "flag", false, new string[] { "flag" }, 0, int.MinValue)]
// Valid name, invalid following
[InlineData(InputType.Int32, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
[InlineData(InputType.Int32, "flag", false, new string[] { "flag", "invalid" }, 0, int.MinValue)]
// Valid name, valid following
[InlineData(InputType.Int32, "flag", true, new string[] { "flag", "1" }, 0, (int)1)]
[InlineData(InputType.Int32, "flag", true, new string[] { "flag", "-1" }, 0, (int)-1)]
public void ProcessAsInt32Test(InputType type, string name, bool required, string[] parts, int index, int? expected)
{
Input input = new Input(type, name, required);
int? actual = input.ProcessAsInt32(parts, ref index);
Assert.Equal(expected, actual);
}
#endregion
#region ProcessAsUInt32
[Theory]
// Invalid type
[InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
// Invalid parts
[InlineData(InputType.UInt32, "flag", true, new string[0], 0, null)]
// Invalid index
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, -1, null)]
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 1, null)]
// Invalid name
[InlineData(InputType.UInt32, "flag", true, new string[] { "" }, 0, null)]
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag2" }, 0, null)]
// Valid name, no following
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt32, "flag", false, new string[] { "flag" }, 0, uint.MinValue)]
// Valid name, invalid following
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
[InlineData(InputType.UInt32, "flag", false, new string[] { "flag", "invalid" }, 0, uint.MinValue)]
// Valid name, valid following
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag", "1" }, 0, (uint)1)]
public void ProcessAsUInt32Test(InputType type, string name, bool required, string[] parts, int index, uint? expected)
{
Input input = new Input(type, name, required);
uint? actual = input.ProcessAsUInt32(parts, ref index);
Assert.Equal(expected, actual);
}
#endregion
#region ProcessAsInt64
[Theory]
// Invalid type
[InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
// Invalid parts
[InlineData(InputType.Int64, "flag", true, new string[0], 0, null)]
// Invalid index
[InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, -1, null)]
[InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 1, null)]
// Invalid name
[InlineData(InputType.Int64, "flag", true, new string[] { "" }, 0, null)]
[InlineData(InputType.Int64, "flag", true, new string[] { "flag2" }, 0, null)]
// Valid name, no following
[InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int64, "flag", false, new string[] { "flag" }, 0, long.MinValue)]
// Valid name, invalid following
[InlineData(InputType.Int64, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
[InlineData(InputType.Int64, "flag", false, new string[] { "flag", "invalid" }, 0, long.MinValue)]
// Valid name, valid following
[InlineData(InputType.Int64, "flag", true, new string[] { "flag", "1" }, 0, (long)1)]
[InlineData(InputType.Int64, "flag", true, new string[] { "flag", "-1" }, 0, (long)-1)]
public void ProcessAsInt64Test(InputType type, string name, bool required, string[] parts, int index, long? expected)
{
Input input = new Input(type, name, required);
long? actual = input.ProcessAsInt64(parts, ref index);
Assert.Equal(expected, actual);
}
#endregion
#region ProcessAsUInt64
[Theory]
// Invalid type
[InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
// Invalid parts
[InlineData(InputType.UInt64, "flag", true, new string[0], 0, null)]
// Invalid index
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, -1, null)]
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 1, null)]
// Invalid name
[InlineData(InputType.UInt64, "flag", true, new string[] { "" }, 0, null)]
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag2" }, 0, null)]
// Valid name, no following
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt64, "flag", false, new string[] { "flag" }, 0, ulong.MinValue)]
// Valid name, invalid following
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
[InlineData(InputType.UInt64, "flag", false, new string[] { "flag", "invalid" }, 0, ulong.MinValue)]
// Valid name, valid following
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag", "1" }, 0, (ulong)1)]
public void ProcessAsUInt64Test(InputType type, string name, bool required, string[] parts, int index, ulong? expected)
{
Input input = new Input(type, name, required);
ulong? actual = input.ProcessAsUInt64(parts, ref index);
Assert.Equal(expected, actual);
}
#endregion
#region ProcessAsString
[Theory]
// Invalid type
[InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
// Invalid parts
[InlineData(InputType.String, "flag", true, new string[0], 0, null)]
// Invalid index
[InlineData(InputType.String, "flag", true, new string[] { "flag" }, -1, null)]
[InlineData(InputType.String, "flag", true, new string[] { "flag" }, 1, null)]
// Invalid name
[InlineData(InputType.String, "flag", true, new string[] { "" }, 0, null)]
[InlineData(InputType.String, "flag", true, new string[] { "flag2" }, 0, null)]
// Valid name, no following
[InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
[InlineData(InputType.String, "flag", false, new string[] { "flag" }, 0, "")]
// Valid name, following
[InlineData(InputType.String, "flag", true, new string[] { "flag", "value" }, 0, "value")]
public void ProcessAsString(InputType type, string name, bool required, string[] parts, int index, string? expected)
{
Input input = new Input(type, name, required);
string? actual = input.ProcessAsString(parts, ref index);
Assert.Equal(expected, actual);
}
#endregion
#region DoesExist
[Fact]
public void DoesExist_Empty_False()
{
string[] parts = [];
int index = 0;
bool actual = Input.DoesExist(parts, index);
Assert.False(actual);
}
[Fact]
public void DoesExist_Negative_False()
{
string[] parts = ["item"];
int index = -1;
bool actual = Input.DoesExist(parts, index);
Assert.False(actual);
}
[Fact]
public void DoesExist_Greater_False()
{
string[] parts = ["item"];
int index = 1;
bool actual = Input.DoesExist(parts, index);
Assert.False(actual);
}
[Fact]
public void DoesExist_Valid_True()
{
string[] parts = ["item"];
int index = 0;
bool actual = Input.DoesExist(parts, index);
Assert.True(actual);
}
#endregion
#region ExtractFactorFromValue
[Theory]
[InlineData("1", "1", 1)]
[InlineData("1c", "1", 1)]
[InlineData("1w", "1", 2)]
[InlineData("1d", "1", 4)]
[InlineData("1q", "1", 8)]
[InlineData("1k", "1", 1024)]
[InlineData("1M", "1", 1024 * 1024)]
[InlineData("1G", "1", 1024 * 1024 * 1024)]
public void ExtractFactorFromValueTest(string value, string expected, long expectedFactor)
{
string actual = Input.ExtractFactorFromValue(value, out long factor);
Assert.Equal(expected, actual);
Assert.Equal(expectedFactor, factor);
}
#endregion
#region RemoveHexIdentifier
[Theory]
[InlineData("", "")]
[InlineData("0", "0")]
[InlineData("00", "00")]
[InlineData("0x", "0x")]
[InlineData("0X", "0X")]
[InlineData("A", "A")]
[InlineData("A0", "A0")]
[InlineData("Ax", "Ax")]
[InlineData("AX", "AX")]
[InlineData("012345", "012345")]
[InlineData("0x12345", "12345")]
[InlineData("0X12345", "12345")]
public void RemoveHexIdentifierTest(string value, string expected)
{
string actual = Input.RemoveHexIdentifier(value);
Assert.Equal(expected, actual);
}
#endregion
}
}

View File

@@ -0,0 +1,753 @@
using System;
using System.Globalization;
namespace MPF.ExecutionContexts
{
/// <summary>
/// Indicates the input type
/// </summary>
public enum InputType
{
None,
Flag,
Boolean,
Int8,
UInt8,
Int16,
UInt16,
Int32,
UInt32,
Int64,
UInt64,
String,
}
/// <summary>
/// Represents a single input for an execution context
/// </summary>
public class Input
{
#region Properties
/// <summary>
/// Input type for parsing
/// </summary>
public readonly InputType InputType;
/// <summary>
/// Primary name for the input
/// </summary>
public readonly string Name;
/// <summary>
/// Verbose name for the input
/// </summary>
private readonly string? _longName;
/// <summary>
/// Indicates if the value following is required or not
/// </summary>
private readonly bool _required;
#endregion
#region Constructors
/// <param name="type">Type of input for parsing</param>
/// <param name="name">Flag name / value</param>
public Input(InputType type, string name)
{
InputType = type;
Name = name;
_longName = null;
_required = true;
}
/// <param name="type">Type of input for parsing</param>
/// <param name="name">Flag name / value</param>
/// <param name="required">Indicates if a following value is required</param>
public Input(InputType type, string name, bool required)
{
InputType = type;
Name = name;
_longName = null;
_required = required;
}
/// <param name="type">Type of input for parsing</param>
/// <param name="shortName">Flag name / value</param>
/// <param name="longName">Verbose flag name / value</param>
public Input(InputType type, string shortName, string longName)
{
InputType = type;
Name = shortName;
_longName = longName;
_required = true;
}
/// <param name="type">Type of input for parsing</param>
/// <param name="shortName">Flag name / value</param>
/// <param name="longName">Verbose flag name / value</param>
/// <param name="required">Indicates if a following value is required</param>
public Input(InputType type, string shortName, string longName, bool required)
{
InputType = type;
Name = shortName;
_longName = longName;
_required = required;
}
#endregion
#region Processors
/// <summary>
/// Process the input as a flag
/// </summary>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="index">Reference to the position in the parts</param>
/// <returns>True if the flag was set, false otherwise</returns>
public bool ProcessAsFlag(string[] parts, ref int index)
{
// Check the input type
if (InputType != InputType.Flag)
return false;
// Check the parts array
if (parts.Length == 0)
return false;
// Check the index
if (index < 0 || index >= parts.Length)
return false;
// Check the name
if (parts[index] == Name || (_longName != null && parts[index] == _longName))
return true;
return false;
}
/// <summary>
/// Process the input as a boolean
/// </summary>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="index">Reference to the position in the parts</param>
/// <returns>Boolean value if set, null otherwise</returns>
public bool? ProcessAsBoolean(string[] parts, ref int index)
{
// Check the input type
if (InputType != InputType.Boolean)
return null;
// Check the parts array
if (parts == null || parts.Length == 0)
return null;
// Check the index
if (index < 0 || index >= parts.Length)
return null;
// Check the name
if (parts[index] == Name || (_longName != null && parts[index] == _longName))
{
// Ensure the value exists
if (!DoesExist(parts, index + 1))
return _required ? null : true;
// If the next value is valid
if (!bool.TryParse(parts[index + 1], out bool value))
return _required ? null : true;
index++;
return value;
}
return null;
}
/// <summary>
/// Process the input as an Int8
/// </summary>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="index">Reference to the position in the parts</param>
/// <returns>Int8 value if set, minimum value if not required and missing, null otherwise</returns>
public sbyte? ProcessAsInt8(string[] parts, ref int index)
{
// Check the input type
if (InputType != InputType.Int8)
return null;
// Check the parts array
if (parts == null || parts.Length == 0)
return null;
// Check the index
if (index < 0 || index >= parts.Length)
return null;
// Check the name
if (parts[index] == Name || (_longName != null && parts[index] == _longName))
{
// Ensure the value exists
if (!DoesExist(parts, index + 1))
return _required ? null : sbyte.MinValue;
// If the next value is valid
if (sbyte.TryParse(parts[index + 1], out sbyte value))
{
index++;
return value;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
if (sbyte.TryParse(baseVal, out value))
{
index++;
return (sbyte)(value * factor);
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (sbyte.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
index++;
return (sbyte)(value * factor);
}
// Return value based on required flag
return _required ? null : sbyte.MinValue;
}
return null;
}
/// <summary>
/// Process the input as a UInt8
/// </summary>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="index">Reference to the position in the parts</param>
/// <returns>UInt8 value if set, minimum value if not required and missing, null otherwise</returns>
public byte? ProcessAsUInt8(string[] parts, ref int index)
{
// Check the input type
if (InputType != InputType.UInt8)
return null;
// Check the parts array
if (parts == null || parts.Length == 0)
return null;
// Check the index
if (index < 0 || index >= parts.Length)
return null;
// Check the name
if (parts[index] == Name || (_longName != null && parts[index] == _longName))
{
// Ensure the value exists
if (!DoesExist(parts, index + 1))
return _required ? null : byte.MinValue;
// If the next value is valid
if (byte.TryParse(parts[index + 1], out byte value))
{
index++;
return value;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
if (byte.TryParse(baseVal, out value))
{
index++;
return (byte)(value * factor);
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (byte.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
index++;
return (byte)(value * factor);
}
// Return value based on required flag
return _required ? null : byte.MinValue;
}
return null;
}
/// <summary>
/// Process the input as an Int16
/// </summary>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="index">Reference to the position in the parts</param>
/// <returns>Int16 value if set, minimum value if not required and missing, null otherwise</returns>
public short? ProcessAsInt16(string[] parts, ref int index)
{
// Check the input type
if (InputType != InputType.Int16)
return null;
// Check the parts array
if (parts == null || parts.Length == 0)
return null;
// Check the index
if (index < 0 || index >= parts.Length)
return null;
// Check the name
if (parts[index] == Name || (_longName != null && parts[index] == _longName))
{
// Ensure the value exists
if (!DoesExist(parts, index + 1))
return _required ? null : short.MinValue;
// If the next value is valid
if (short.TryParse(parts[index + 1], out short value))
{
index++;
return value;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
if (short.TryParse(baseVal, out value))
{
index++;
return (short)(value * factor);
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (short.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
index++;
return (short)(value * factor);
}
// Return value based on required flag
return _required ? null : short.MinValue;
}
return null;
}
/// <summary>
/// Process the input as a UInt16
/// </summary>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="index">Reference to the position in the parts</param>
/// <returns>UInt16 value if set, minimum value if not required and missing, null otherwise</returns>
public ushort? ProcessAsUInt16(string[] parts, ref int index)
{
// Check the input type
if (InputType != InputType.UInt16)
return null;
// Check the parts array
if (parts == null || parts.Length == 0)
return null;
// Check the index
if (index < 0 || index >= parts.Length)
return null;
// Check the name
if (parts[index] == Name || (_longName != null && parts[index] == _longName))
{
// Ensure the value exists
if (!DoesExist(parts, index + 1))
return _required ? null : ushort.MinValue;
// If the next value is valid
if (ushort.TryParse(parts[index + 1], out ushort value))
{
index++;
return value;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
if (ushort.TryParse(baseVal, out value))
{
index++;
return (ushort)(value * factor);
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (ushort.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
index++;
return (ushort)(value * factor);
}
// Return value based on required flag
return _required ? null : ushort.MinValue;
}
return null;
}
/// <summary>
/// Process the input as an Int32
/// </summary>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="index">Reference to the position in the parts</param>
/// <returns>Int32 value if set, minimum value if not required and missing, null otherwise</returns>
public int? ProcessAsInt32(string[] parts, ref int index)
{
// Check the input type
if (InputType != InputType.Int32)
return null;
// Check the parts array
if (parts == null || parts.Length == 0)
return null;
// Check the index
if (index < 0 || index >= parts.Length)
return null;
// Check the name
if (parts[index] == Name || (_longName != null && parts[index] == _longName))
{
// Ensure the value exists
if (!DoesExist(parts, index + 1))
return _required ? null : int.MinValue;
// If the next value is valid
if (int.TryParse(parts[index + 1], out int value))
{
index++;
return value;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
if (int.TryParse(baseVal, out value))
{
index++;
return (int)(value * factor);
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (int.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
index++;
return (int)(value * factor);
}
// Return value based on required flag
return _required ? null : int.MinValue;
}
return null;
}
/// <summary>
/// Process the input as a UInt32
/// </summary>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="index">Reference to the position in the parts</param>
/// <returns>UInt32 value if set, minimum value if not required and missing, null otherwise</returns>
public uint? ProcessAsUInt32(string[] parts, ref int index)
{
// Check the input type
if (InputType != InputType.UInt32)
return null;
// Check the parts array
if (parts == null || parts.Length == 0)
return null;
// Check the index
if (index < 0 || index >= parts.Length)
return null;
// Check the name
if (parts[index] == Name || (_longName != null && parts[index] == _longName))
{
// Ensure the value exists
if (!DoesExist(parts, index + 1))
return _required ? null : uint.MinValue;
// If the next value is valid
if (uint.TryParse(parts[index + 1], out uint value))
{
index++;
return value;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
if (uint.TryParse(baseVal, out value))
{
index++;
return (uint)(value * factor);
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (uint.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
index++;
return (uint)(value * factor);
}
// Return value based on required flag
return _required ? null : uint.MinValue;
}
return null;
}
/// <summary>
/// Process the input as an Int64
/// </summary>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="index">Reference to the position in the parts</param>
/// <returns>Int64 value if set, minimum value if not required and missing, null otherwise</returns>
public long? ProcessAsInt64(string[] parts, ref int index)
{
// Check the input type
if (InputType != InputType.Int64)
return null;
// Check the parts array
if (parts == null || parts.Length == 0)
return null;
// Check the index
if (index < 0 || index >= parts.Length)
return null;
// Check the name
if (parts[index] == Name || (_longName != null && parts[index] == _longName))
{
// Ensure the value exists
if (!DoesExist(parts, index + 1))
return _required ? null : long.MinValue;
// If the next value is valid
if (long.TryParse(parts[index + 1], out long value))
{
index++;
return value;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
if (long.TryParse(baseVal, out value))
{
index++;
return (long)(value * factor);
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (long.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
index++;
return (long)(value * factor);
}
// Return value based on required flag
return _required ? null : long.MinValue;
}
return null;
}
/// <summary>
/// Process the input as a UInt64
/// </summary>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="index">Reference to the position in the parts</param>
/// <returns>UInt64 value if set, minimum value if not required and missing, null otherwise</returns>
public ulong? ProcessAsUInt64(string[] parts, ref int index)
{
// Check the input type
if (InputType != InputType.UInt64)
return null;
// Check the parts array
if (parts == null || parts.Length == 0)
return null;
// Check the index
if (index < 0 || index >= parts.Length)
return null;
// Check the name
if (parts[index] == Name || (_longName != null && parts[index] == _longName))
{
// Ensure the value exists
if (!DoesExist(parts, index + 1))
return _required ? null : ulong.MinValue;
// If the next value is valid
if (ulong.TryParse(parts[index + 1], out ulong value))
{
index++;
return value;
}
// Try to process as a formatted string
string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
if (ulong.TryParse(baseVal, out value))
{
index++;
return (ulong)(value * (ulong)factor);
}
// Try to process as a hex string
string hexValue = RemoveHexIdentifier(baseVal);
if (ulong.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
{
index++;
return (ulong)(value * (ulong)factor);
}
// Return value based on required flag
return _required ? null : ulong.MinValue;
}
return null;
}
/// <summary>
/// Process the input as a UInt64
/// </summary>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="index">Reference to the position in the parts</param>
/// <returns>String value if set, empty value if not required and missing, null otherwise</returns>
public string? ProcessAsString(string[] parts, ref int index)
{
// Check the input type
if (InputType != InputType.String)
return null;
// Check the parts array
if (parts == null || parts.Length == 0)
return null;
// Check the index
if (index < 0 || index >= parts.Length)
return null;
// Check the name
if (parts[index] == Name || (_longName != null && parts[index] == _longName))
{
// Ensure the value exists
if (!DoesExist(parts, index + 1))
return _required ? null : string.Empty;
index++;
return parts[index];
}
return null;
}
#endregion
#region Helpers
/// <summary>
/// Returns whether or not the selected item exists
/// </summary>
/// <param name="parts">Parts array to be referenced</param>
/// <param name="index">Current index</param>
/// <returns>True if the next item exists, false otherwise</returns>
internal static bool DoesExist(string[] parts, int index)
=> index >= 0 && index < parts.Length;
/// <summary>
/// Get the trimmed value and multiplication factor from a value
/// </summary>
/// <param name="value">String value to treat as suffixed number</param>
/// <returns>Trimmed value and multiplication factor</returns>
internal static string ExtractFactorFromValue(string value, out long factor)
{
value = value.Trim('"');
factor = 1;
// Characters
if (value.EndsWith("c", StringComparison.Ordinal))
{
factor = 1;
value = value.TrimEnd('c');
}
// Words
else if (value.EndsWith("w", StringComparison.Ordinal))
{
factor = 2;
value = value.TrimEnd('w');
}
// Double Words
else if (value.EndsWith("d", StringComparison.Ordinal))
{
factor = 4;
value = value.TrimEnd('d');
}
// Quad Words
else if (value.EndsWith("q", StringComparison.Ordinal))
{
factor = 8;
value = value.TrimEnd('q');
}
// Kilobytes
else if (value.EndsWith("k", StringComparison.Ordinal))
{
factor = 1024;
value = value.TrimEnd('k');
}
// Megabytes
else if (value.EndsWith("M", StringComparison.Ordinal))
{
factor = 1024 * 1024;
value = value.TrimEnd('M');
}
// Gigabytes
else if (value.EndsWith("G", StringComparison.Ordinal))
{
factor = 1024 * 1024 * 1024;
value = value.TrimEnd('G');
}
return value;
}
/// <summary>
/// Removes a leading 0x if it exists, case insensitive
/// </summary>
/// <param name="value">String with removed leading 0x</param>
/// <returns></returns>
internal static string RemoveHexIdentifier(string value)
{
if (value.Length <= 2)
return value;
if (value[0] != '0')
return value;
if (value[1] != 'x' && value[1] != 'X')
return value;
return value.Substring(2);
}
#endregion
}
}