Skip to content

Commit 276391c

Browse files
atruskienatemcmaster
authored andcommitted
Adds support for float and double types
This commit allows the CommandLineUtils to parse: - doubles - floats - and nullable variants of both It also infers the CommandOptionType in the same manner that is done for integers.
1 parent 1b9c558 commit 276391c

File tree

6 files changed

+128
-1
lines changed

6 files changed

+128
-1
lines changed

src/CommandLineUtils/Internal/CommandOptionTypeMapper.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ public CommandOptionType GetOptionType(Type clrType)
6262
|| typeof(long) == clrType
6363
|| typeof(ushort) == clrType
6464
|| typeof(uint) == clrType
65-
|| typeof(ulong) == clrType)
65+
|| typeof(ulong) == clrType
66+
|| typeof(float) == clrType
67+
|| typeof(double) == clrType)
6668
{
6769
return CommandOptionType.SingleValue;
6870
}

src/CommandLineUtils/Internal/ValueParserProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ internal class ValueParserProvider
2222
{ typeof(ushort), UInt16ValueParser.Singleton },
2323
{ typeof(uint), UInt32ValueParser.Singleton },
2424
{ typeof(ulong), UInt64ValueParser.Singleton },
25+
{ typeof(float), FloatValueParser.Singleton },
26+
{ typeof(double), DoubleValueParser.Singleton },
2527
};
2628

2729
private ValueParserProvider()
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) Nate McMaster.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace McMaster.Extensions.CommandLineUtils.ValueParsers
5+
{
6+
internal class DoubleValueParser : IValueParser
7+
{
8+
private DoubleValueParser()
9+
{ }
10+
11+
public static DoubleValueParser Singleton { get; } = new DoubleValueParser();
12+
13+
public object Parse(string argName, string value)
14+
{
15+
if (!double.TryParse(value, out var result))
16+
{
17+
throw new CommandParsingException(null, $"Invalid value specified for {argName}. '{value}' is not a valid floating-point number.");
18+
}
19+
return result;
20+
}
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) Nate McMaster.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
namespace McMaster.Extensions.CommandLineUtils.ValueParsers
5+
{
6+
internal class FloatValueParser : IValueParser
7+
{
8+
private FloatValueParser()
9+
{ }
10+
11+
public static FloatValueParser Singleton { get; } = new FloatValueParser();
12+
13+
public object Parse(string argName, string value)
14+
{
15+
if (!float.TryParse(value, out var result))
16+
{
17+
throw new CommandParsingException(null, $"Invalid value specified for {argName}. '{value}' is not a valid floating-point number.");
18+
}
19+
return result;
20+
}
21+
}
22+
}

test/CommandLineUtils.Tests/CommandOptionTypeMapperTests.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,17 @@ public class CommandOptionTypeMapperTests
1919
[InlineData(typeof(uint), CommandOptionType.SingleValue)]
2020
[InlineData(typeof(ulong), CommandOptionType.SingleValue)]
2121
[InlineData(typeof(ushort), CommandOptionType.SingleValue)]
22+
[InlineData(typeof(float), CommandOptionType.SingleValue)]
23+
[InlineData(typeof(double), CommandOptionType.SingleValue)]
2224
[InlineData(typeof(byte?), CommandOptionType.SingleValue)]
2325
[InlineData(typeof(short?), CommandOptionType.SingleValue)]
2426
[InlineData(typeof(int?), CommandOptionType.SingleValue)]
2527
[InlineData(typeof(long?), CommandOptionType.SingleValue)]
2628
[InlineData(typeof(ushort?), CommandOptionType.SingleValue)]
2729
[InlineData(typeof(uint?), CommandOptionType.SingleValue)]
2830
[InlineData(typeof(ulong?), CommandOptionType.SingleValue)]
31+
[InlineData(typeof(float?), CommandOptionType.SingleValue)]
32+
[InlineData(typeof(double?), CommandOptionType.SingleValue)]
2933
[InlineData(typeof(string), CommandOptionType.SingleValue)]
3034
[InlineData(typeof(byte[]), CommandOptionType.MultipleValue)]
3135
[InlineData(typeof(short[]), CommandOptionType.MultipleValue)]

test/CommandLineUtils.Tests/ValueParserProviderTests.cs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
namespace McMaster.Extensions.CommandLineUtils.Tests
88
{
9+
using System.Globalization;
10+
911
public class ValueParserProviderTests
1012
{
1113
public enum Color
@@ -29,6 +31,12 @@ private class Program
2931
[Option("--int64")]
3032
public long Int64 { get; }
3133

34+
[Option("--float")]
35+
public float Float { get; }
36+
37+
[Option("--double")]
38+
public double Double { get; }
39+
3240
[Option("--bool", CommandOptionType.SingleValue)]
3341
public bool Bool { get; }
3442

@@ -41,6 +49,12 @@ private class Program
4149
[Option("--int64-opt")]
4250
public long? Int64Opt { get; }
4351

52+
[Option("--float-opt")]
53+
public float? FloatOpt { get; }
54+
55+
[Option("--double-opt")]
56+
public double? DoubleOpt { get; }
57+
4458
[Option("--uint32")]
4559
public uint UInt32 { get; }
4660

@@ -66,6 +80,17 @@ private class Program
6680
public Color ColorOption { get; }
6781
}
6882

83+
public static IEnumerable<object[]> GetFloatingPointSymbolsData()
84+
{
85+
var format = CultureInfo.CurrentCulture.NumberFormat;
86+
return new[]
87+
{
88+
new object[] { format.PositiveInfinitySymbol, float.PositiveInfinity },
89+
new object[] { format.NegativeInfinitySymbol, float.NegativeInfinity },
90+
new object[] { format.NaNSymbol, float.NaN},
91+
};
92+
}
93+
6994
[Theory]
7095
[InlineData("255", byte.MaxValue)]
7196
[InlineData("1", 1)]
@@ -130,6 +155,56 @@ public void ParsesLongNullable(string arg, long? result)
130155
Assert.Equal(result, parsed.Int64Opt);
131156
}
132157

158+
[Theory]
159+
[InlineData("0.0", 0.0f)]
160+
[InlineData("123456789.987654321", 123456789.987654321f)]
161+
[InlineData("-123.456", -123.456f)]
162+
[InlineData("-1E10", -1E10f)]
163+
[MemberData(nameof(GetFloatingPointSymbolsData))]
164+
public void ParsesFloat(string arg, float result)
165+
{
166+
var parsed = CommandLineParser.ParseArgs<Program>("--float", arg);
167+
Assert.Equal(result, parsed.Float);
168+
}
169+
170+
[Theory]
171+
[InlineData("0.0", 0.0)]
172+
[InlineData("123456789.987654321", 123456789.987654321)]
173+
[InlineData("-123.456", -123.456)]
174+
[InlineData("-1E10", -1E10)]
175+
[MemberData(nameof(GetFloatingPointSymbolsData))]
176+
public void ParsesDouble(string arg, double result)
177+
{
178+
var parsed = CommandLineParser.ParseArgs<Program>("--double", arg);
179+
Assert.Equal(result, parsed.Double);
180+
}
181+
182+
[Theory]
183+
[InlineData("0.0", 0.0f)]
184+
[InlineData("123456789.987654321", 123456789.987654321f)]
185+
[InlineData("-123.456", -123.456f)]
186+
[InlineData("-1E10", -1E10f)]
187+
[MemberData(nameof(GetFloatingPointSymbolsData))]
188+
[InlineData("", null)]
189+
public void ParsesFloatNullable(string arg, float? result)
190+
{
191+
var parsed = CommandLineParser.ParseArgs<Program>("--float-opt", arg);
192+
Assert.Equal(result, parsed.FloatOpt);
193+
}
194+
195+
[Theory]
196+
[InlineData("0.0", 0.0)]
197+
[InlineData("123456789.987654321", 123456789.987654321)]
198+
[InlineData("-123.456", -123.456)]
199+
[InlineData("-1E10", -1E10)]
200+
[MemberData(nameof(GetFloatingPointSymbolsData))]
201+
[InlineData("", null)]
202+
public void ParsesDoubleNullable(string arg, double? result)
203+
{
204+
var parsed = CommandLineParser.ParseArgs<Program>("--double-opt", arg);
205+
Assert.Equal(result, parsed.DoubleOpt);
206+
}
207+
133208
[Theory]
134209
[InlineData("true", true)]
135210
[InlineData("True", true)]

0 commit comments

Comments
 (0)