Skip to content

Commit b46865d

Browse files
committed
Merge branch 'johnjaylward-ExposeValueAndErrorOnParserResult' by @johnjaylwar into develop
2 parents 4d00c9e + 25315f2 commit b46865d

File tree

2 files changed

+136
-29
lines changed

2 files changed

+136
-29
lines changed

src/CommandLine/ParserResult.cs

+28-29
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace CommandLine
99
public sealed class TypeInfo
1010
{
1111
private readonly Type current;
12-
private readonly IEnumerable<Type> choices;
12+
private readonly IEnumerable<Type> choices;
1313

1414
private TypeInfo(Type current, IEnumerable<Type> choices)
1515
{
@@ -64,10 +64,20 @@ public abstract class ParserResult<T>
6464
private readonly ParserResultType tag;
6565
private readonly TypeInfo typeInfo;
6666

67-
internal ParserResult(ParserResultType tag, TypeInfo typeInfo)
67+
internal ParserResult(IEnumerable<Error> errors, TypeInfo typeInfo)
6868
{
69-
this.tag = tag;
70-
this.typeInfo = typeInfo;
69+
this.tag = ParserResultType.NotParsed;
70+
this.typeInfo = typeInfo ?? TypeInfo.Create(typeof(T));
71+
Errors = errors ?? new Error[0];
72+
Value = default;
73+
}
74+
75+
internal ParserResult(T value, TypeInfo typeInfo)
76+
{
77+
Value = value ?? throw new ArgumentNullException(nameof(value));
78+
this.tag = ParserResultType.Parsed;
79+
this.typeInfo = typeInfo ?? TypeInfo.Create(value.GetType());
80+
Errors = new Error[0];
7181
}
7282

7383
/// <summary>
@@ -82,6 +92,16 @@ public TypeInfo TypeInfo
8292
{
8393
get { return typeInfo; }
8494
}
95+
96+
/// <summary>
97+
/// Gets the instance with parsed values. If one or more errors occures, <see langword="default"/> is returned.
98+
/// </summary>
99+
public T Value { get; }
100+
101+
/// <summary>
102+
/// Gets the sequence of parsing errors. If there are no errors, then an empty IEnumerable is returned.
103+
/// </summary>
104+
public IEnumerable<Error> Errors { get; }
85105
}
86106

87107
/// <summary>
@@ -90,26 +110,16 @@ public TypeInfo TypeInfo
90110
/// <typeparam name="T">The type with attributes that define the syntax of parsing rules.</typeparam>
91111
public sealed class Parsed<T> : ParserResult<T>, IEquatable<Parsed<T>>
92112
{
93-
private readonly T value;
94-
95113
internal Parsed(T value, TypeInfo typeInfo)
96-
: base(ParserResultType.Parsed, typeInfo)
114+
: base(value, typeInfo)
97115
{
98-
this.value = value;
99116
}
100117

101118
internal Parsed(T value)
102119
: this(value, TypeInfo.Create(value.GetType()))
103120
{
104121
}
105122

106-
/// <summary>
107-
/// Gets the instance with parsed values.
108-
/// </summary>
109-
public T Value
110-
{
111-
get { return value; }
112-
}
113123

114124
/// <summary>
115125
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="System.Object"/>.
@@ -118,8 +128,7 @@ public T Value
118128
/// <returns><value>true</value> if the specified <see cref="System.Object"/> is equal to the current <see cref="System.Object"/>; otherwise, <value>false</value>.</returns>
119129
public override bool Equals(object obj)
120130
{
121-
var other = obj as Parsed<T>;
122-
if (other != null)
131+
if (obj is Parsed<T> other)
123132
{
124133
return Equals(other);
125134
}
@@ -159,21 +168,12 @@ public bool Equals(Parsed<T> other)
159168
/// <typeparam name="T">The type with attributes that define the syntax of parsing rules.</typeparam>
160169
public sealed class NotParsed<T> : ParserResult<T>, IEquatable<NotParsed<T>>
161170
{
162-
private readonly IEnumerable<Error> errors;
163171

164172
internal NotParsed(TypeInfo typeInfo, IEnumerable<Error> errors)
165-
: base(ParserResultType.NotParsed, typeInfo)
173+
: base(errors, typeInfo)
166174
{
167-
this.errors = errors;
168175
}
169176

170-
/// <summary>
171-
/// Gets the sequence of parsing errors.
172-
/// </summary>
173-
public IEnumerable<Error> Errors
174-
{
175-
get { return errors; }
176-
}
177177

178178
/// <summary>
179179
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="System.Object"/>.
@@ -182,8 +182,7 @@ public IEnumerable<Error> Errors
182182
/// <returns><value>true</value> if the specified <see cref="System.Object"/> is equal to the current <see cref="System.Object"/>; otherwise, <value>false</value>.</returns>
183183
public override bool Equals(object obj)
184184
{
185-
var other = obj as NotParsed<T>;
186-
if (other != null)
185+
if (obj is NotParsed<T> other)
187186
{
188187
return Equals(other);
189188
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using Xunit;
4+
using CommandLine.Text;
5+
6+
namespace CommandLine.Tests.Unit
7+
{
8+
//Reference: PR# 634
9+
public class Issue543Tests
10+
{
11+
12+
private const int ERROR_SUCCESS = 0;
13+
14+
[Fact]
15+
public void Parser_GiveHelpArgument_ExpectSuccess()
16+
{
17+
var result = Parser.Default.ParseArguments<Options>(new[] { "--help" });
18+
19+
Assert.Equal(ParserResultType.NotParsed, result.Tag);
20+
Assert.Null(result.Value);
21+
Assert.NotEmpty(result.Errors);
22+
}
23+
24+
[Fact]
25+
public void Parser_GiveConnectionStringAndJobId_ExpectSuccess()
26+
{
27+
var result = Parser.Default.ParseArguments<Options>(new[] {
28+
"-c", "someConnectionString",
29+
"-j", "1234",
30+
});
31+
32+
Assert.Equal(ParserResultType.Parsed, result.Tag);
33+
Assert.NotNull(result.Value);
34+
Assert.Empty(result.Errors);
35+
Assert.Equal("someConnectionString", result.Value.ConnectionString);
36+
Assert.Equal(1234, result.Value.JobId);
37+
}
38+
39+
[Fact]
40+
public void Parser_GiveVerb1_ExpectSuccess()
41+
{
42+
var result = Parser.Default.ParseArguments<Verb1Options, Verb2Options>(new[] {
43+
"verb1",
44+
"-j", "1234",
45+
});
46+
47+
Assert.Equal(ParserResultType.Parsed, result.Tag);
48+
Assert.Empty(result.Errors);
49+
Assert.NotNull(result.Value);
50+
Assert.NotNull(result.Value as Verb1Options);
51+
Assert.Equal(1234, (result.Value as Verb1Options).JobId);
52+
}
53+
54+
[Fact]
55+
public void Parser_GiveVerb2_ExpectSuccess()
56+
{
57+
var result = Parser.Default.ParseArguments<Verb1Options, Verb2Options>(new[] {
58+
"verb2",
59+
"-c", "someConnectionString",
60+
});
61+
62+
Assert.Equal(ParserResultType.Parsed, result.Tag);
63+
Assert.Empty(result.Errors);
64+
Assert.NotNull(result.Value);
65+
Assert.NotNull(result.Value as Verb2Options);
66+
Assert.Equal("someConnectionString", (result.Value as Verb2Options).ConnectionString);
67+
}
68+
69+
// Options
70+
internal class Options
71+
{
72+
[Option('c', "connectionString", Required = true, HelpText = "Texts.ExplainConnection")]
73+
public string ConnectionString { get; set; }
74+
75+
[Option('j', "jobId", Required = true, HelpText = "Texts.ExplainJob")]
76+
public int JobId { get; set; }
77+
78+
[Usage(ApplicationAlias = "Importer.exe")]
79+
public static IEnumerable<Example> Examples
80+
{
81+
get => new[] {
82+
new Example("Texts.ExplainExampleExecution", new Options() {
83+
ConnectionString="Server=MyServer;Database=MyDatabase",
84+
JobId = 5
85+
}),
86+
};
87+
}
88+
}
89+
90+
// Options
91+
[Verb("verb1")]
92+
internal class Verb1Options
93+
{
94+
[Option('j', "jobId", Required = false, HelpText = "Texts.ExplainJob")]
95+
public int JobId { get; set; }
96+
}
97+
98+
// Options
99+
[Verb("verb2")]
100+
internal class Verb2Options
101+
{
102+
[Option('c', "connectionString", Required = false, HelpText = "Texts.ExplainConnection")]
103+
public string ConnectionString { get; set; }
104+
}
105+
106+
}
107+
}
108+

0 commit comments

Comments
 (0)