Skip to content

Commit a69501f

Browse files
atruskienatemcmaster
authored andcommitted
Adds a test for validation of subcommand models
This commit demonstates a failing unit test for command validation in subcommands. Currently the theories on lines 99, 100, and 101 in ValidateMethodConventionTest.cs fail when they should pass (if I understand the intention correctly). The tests on lines 102, 103, and 104 pass and should pass. The root cause seems to be that an initialized model, **but not a model that has had its values bound to args**, is used for validation in subcommands. For main commands (not subcomands) the model used for validation is initialized and has had its values bound - as expected.
1 parent 51997d7 commit a69501f

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

test/CommandLineUtils.Tests/ValidateMethodConventionTests.cs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,87 @@ public void ConventionThrowsIfOnValidateDoesNotReturnValidationresult()
4040
var ex = Assert.Throws<InvalidOperationException>(() => app.Conventions.UseOnValidateMethodFromModel());
4141
Assert.Equal(Strings.InvalidOnValidateReturnType(typeof(ProgramWithBadOnValidate)), ex.Message);
4242
}
43+
44+
45+
[Command]
46+
[Subcommand("subcommand", typeof(SubcommandValidate))]
47+
private class MainValidate
48+
{
49+
[Option]
50+
public int? Middle { get; }
51+
52+
private ValidationResult OnValidate(ValidationContext context, CommandLineContext appContext)
53+
{
54+
if (this.Middle.HasValue && this.Middle < 0)
55+
{
56+
return new ValidationResult("Middle must be greater than 0");
57+
}
58+
59+
Assert.Equal(typeof(CommandLineApplication<MainValidate>), context.ObjectInstance.GetType());
60+
61+
return ValidationResult.Success;
62+
}
63+
}
64+
65+
[Command]
66+
private class SubcommandValidate
67+
{
68+
[Option]
69+
public int Start { get; private set; } = 0;
70+
71+
[Option]
72+
public int End { get; private set; } = Int32.MaxValue;
73+
74+
private ValidationResult OnValidate(ValidationContext context, CommandLineContext appContext)
75+
{
76+
if (this.Start >= this.End)
77+
{
78+
return new ValidationResult("End must be greater than start");
79+
}
80+
81+
Assert.Equal(typeof(CommandLineApplication<SubcommandValidate>), context.ObjectInstance.GetType());
82+
var subcommand = (CommandLineApplication<SubcommandValidate>) context.ObjectInstance;
83+
var main = (CommandLineApplication<MainValidate>) subcommand.Parent;
84+
85+
var middle = main.Model.Middle;
86+
if (middle.HasValue)
87+
{
88+
if (middle.Value < this.Start || middle.Value >= this.End)
89+
{
90+
return new ValidationResult("Middle must be between start and end");
91+
}
92+
}
93+
94+
return ValidationResult.Success;
95+
}
96+
}
97+
98+
[Theory]
99+
[InlineData("subcommand -s 999 -e 123", "End must be greater than start")]
100+
[InlineData("-m 999 subcommand -s 111 -e 123", "Middle must be between start and end")]
101+
[InlineData("-m -5 subcommand -s -100 -e 100", "Middle must be greater than 0")]
102+
[InlineData("-m 111 subcommand", null)]
103+
[InlineData("subcommand -s 111 -e 123", null)]
104+
[InlineData("-m 111 subcommand -s 100 -e 123", null)]
105+
public void ValidatorShouldGetDeserailizedModelInSubcommands(string args, string error)
106+
{
107+
var app = new CommandLineApplication<MainValidate>();
108+
app.Conventions.UseDefaultConventions();
109+
110+
// this tests that the model is actually given values before it passed to command validation
111+
var parseResult = app.Parse(args.Split(' '));
112+
113+
var result = parseResult.ValidationResult;
114+
115+
if (error == null)
116+
{
117+
Assert.Equal(ValidationResult.Success, result);
118+
}
119+
else
120+
{
121+
Assert.NotEqual(ValidationResult.Success, result);
122+
Assert.Equal(error, result.ErrorMessage);
123+
}
124+
}
43125
}
44126
}

0 commit comments

Comments
 (0)