Skip to content

Commit 93b1813

Browse files
authored
Added generation of Get[Required]Option to binder based on the nullability of the type. (#26)
* Default is to use `GetRequiredOption` and only use `GetOption` when the type is explicitly annotated as nullable. * Note: The term 'required' as used in those APIs is in the retrieval of the property value and throws an exception if not specified as an argument. - Nullable types are by definition possibly null and therefore are not considered "Required"
1 parent 4a464b9 commit 93b1813

6 files changed

Lines changed: 20 additions & 9 deletions

File tree

src/Ubiquity.NET.CommandLine.SrcGen.UT/CommandAnalyzerTests.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ public async Task GoldenPath_produces_no_diagnostics( TestRuntime testRuntime )
8686
await analyzerTest.RunAsync( TestContext.CancellationToken );
8787
}
8888

89+
// TODO: Test that a nullable value is not marked as required. (That's a conflicting claim, if it's required it can't be null)
90+
// A nullable type MAY have a default value handler to provide a null default. Additional test - anything with a default
91+
// value provider shouldn't be "required" it's also nonsensical.
92+
8993
private AnalyzerTest<MsTestVerifier> CreateTestRunner( string source, TestRuntime testRuntime )
9094
{
9195
return CreateTestRunner( SourceText.From( source ), testRuntime );

src/Ubiquity.NET.CommandLine.SrcGen.UT/RootCommandAttributeTests.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,6 @@ public async Task Generator_handles_nullable_types( TestRuntime testRuntime )
4040
await runner.RunAsync( TestContext.CancellationToken );
4141
}
4242

43-
// TODO: Test GetOption[Required]Value() for correct behavior
44-
// Nullable types always use GetOptionValue(). // Null is a valid value so it is truly optional.
45-
// non-nullable ref types use GetOptionRequiredValue() // no default is plausible (may provide one using a delegate)
46-
// non-nullable value types use GetOptionValue() // value types have a default value of 0; (May override with delegate)
47-
4843
private SourceGeneratorTest<MsTestVerifier> CreateTestRunner(
4944
SourceText source,
5045
TestRuntime testRuntime,

src/Ubiquity.NET.CommandLine.SrcGen.UT/TestFiles/RootCommandAttributeTests/Basic_golden_path_succeeds/expected.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ public static TestOptions Bind( global::System.CommandLine.ParseResult parseResu
2121
{
2222
return new()
2323
{
24-
SomePath = parseResult.GetValue( Descriptors.SomePath ),
25-
SomeExistingPath = parseResult.GetValue( Descriptors.SomeExistingPath ),
24+
SomePath = parseResult.GetRequiredValue( Descriptors.SomePath ),
25+
SomeExistingPath = parseResult.GetRequiredValue( Descriptors.SomeExistingPath ),
2626
Thing1 = parseResult.GetRequiredValue( Descriptors.Thing1 ),
27-
SomeOtherPath = parseResult.GetValue( Descriptors.SomeOtherPath ),
27+
SomeOtherPath = parseResult.GetRequiredValue( Descriptors.SomeOtherPath ),
2828
};
2929
}
3030

src/Ubiquity.NET.CommandLine.SrcGen.UT/TestFiles/RootCommandAttributeTests/Generator_handles_nullable_types/expected.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public static TestOptions Bind( global::System.CommandLine.ParseResult parseResu
2222
return new()
2323
{
2424
Thing1 = parseResult.GetValue( Descriptors.Thing1 ),
25+
Thing2 = parseResult.GetRequiredValue( Descriptors.Thing2 ),
2526
};
2627
}
2728

@@ -30,6 +31,7 @@ public static TestOptions Bind( global::System.CommandLine.ParseResult parseResu
3031
return new global::Ubiquity.NET.CommandLine.AppControlledDefaultsRootCommand( Settings, "Root command for tests" )
3132
{
3233
Descriptors.Thing1,
34+
Descriptors.Thing2,
3335
};
3436
}
3537
}
@@ -42,5 +44,12 @@ file static class Descriptors
4244
HelpName = "Help name for thing1",
4345
Description = "Test Thing1",
4446
};
47+
48+
internal static readonly global::System.CommandLine.Option<bool> Thing2
49+
= new global::System.CommandLine.Option<bool>("--thing2", "-t")
50+
{
51+
HelpName = "Help name for thing2",
52+
Description = "Test Thing2",
53+
};
4554
}
4655
}

src/Ubiquity.NET.CommandLine.SrcGen.UT/TestFiles/RootCommandAttributeTests/Generator_handles_nullable_types/input.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,7 @@ internal partial class TestOptions
77
{
88
[Option( "--thing1", Aliases = [ "-t" ], Description = "Test Thing1", HelpName = "Help name for thing1" )]
99
public bool? Thing1 { get; init; }
10+
11+
[Option( "--thing2", Aliases = [ "-t" ], Description = "Test Thing2", HelpName = "Help name for thing2" )]
12+
public bool Thing2 { get; init; }
1013
}

src/Ubiquity.NET.CommandLine.SrcGen/Templates/RootCommandClassTemplate.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ private void WriteBindMethod( IndentedTextWriter writer )
7979
{
8080
foreach (PropertyInfo info in Properties)
8181
{
82-
string methodName = info.IsRequired ? "GetRequiredValue" : "GetValue";
82+
string methodName = info.TypeName.IsNullable ? "GetValue" : "GetRequiredValue";
8383
writer.WriteLine($"{info.SimpleName} = parseResult.{methodName}( Descriptors.{info.SimpleName} ),");
8484
}
8585
}

0 commit comments

Comments
 (0)