Skip to content

Conversation

@jonsequitur
Copy link
Contributor

This fixes the following issues:

The approach I took to fix #2573 makes Argument<bool> and Option<bool> have an implicit DefaultValueFactory. This change drove changes to the HelpBuilder so I also fixed #2582 while I was in there.

It's not obvious to me that this is the right fix, so I thought that the PR would help clarify the discussion.

For example, should other types than bool have this behavior of an implicit default value?

@jonsequitur jonsequitur marked this pull request as draft June 27, 2025 17:53
Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you for fixing all the issues @jonsequitur !

switch (this)
{
case Argument<bool> boolArgument:
boolArgument.DefaultValueFactory = _ => false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we can define a static lambda to reuse it for all other boolean arguments

Suggested change
boolArgument.DefaultValueFactory = _ => false;
boolArgument.DefaultValueFactory = static _ => false;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

subjective nit: I am not convinced that switch is the best construct in this case, as it's unlikely that we need other types with such special handling (if should be just fine).

It would be also nice to add a comment explaining why it's needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, if is cleaner. I was considering whether other types should have similar treatment.


internal static Argument None { get; } = new NoArgument();

internal class NoArgument : Argument
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: since all the callers use Argument.None, could it be made private?

Suggested change
internal class NoArgument : Argument
private sealed class NoArgument : Argument


var result = root.Parse("-v -v -v");

using var _ = new AssertionScope();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just for my education: why do we need it here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes the behavior of the assertions so that all will be evaluated and reported even if the first one fails. Multiple assertions in a test is often considered an antipattern because they can fail independently and failing the test on the first assertion failure loses useful information.

The AssertionScope approach provides a way to make sure all assertion results are reported.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes the behavior of the assertions so that all will be evaluated and reported even if the first one fails. Multiple assertions in a test is often considered an antipattern because they can fail independently and failing the test on the first assertion failure loses useful information.

The AssertionScope approach provides a way to make sure all assertion results are reported.

Thanks a lot! It would be great if we could enable it project-wide without a code change (like a csproj setting)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That could be done using a base class (to instantiate this in the constructor and dispose it in Dispose) but I find in well designed tests, multiple assertions aren't the norm and I prefer not to encourage this. One scenario per test should usually guide tests toward one assertion per test.

@jonsequitur jonsequitur marked this pull request as ready for review June 30, 2025 15:34
@jonsequitur jonsequitur force-pushed the fix-some-GetRequiredValue-issues branch from 76d940d to e96ecb3 Compare June 30, 2025 16:00
@jonsequitur jonsequitur merged commit 341d847 into dotnet:main Jun 30, 2025
10 checks passed
@jonsequitur jonsequitur deleted the fix-some-GetRequiredValue-issues branch July 1, 2025 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

When displaying default values do not display [] when value is null GetRequiredValue throws for implicit values

4 participants