mirror of
https://github.com/SabreTools/SabreTools.CommandLine.git
synced 2026-02-04 21:30:16 +00:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47d067df1c | ||
|
|
90bfcc8fe2 | ||
|
|
be081c701d | ||
|
|
66b0e27d4e | ||
|
|
573fe2e160 | ||
|
|
6ad9fa4521 | ||
|
|
a261f428f2 | ||
|
|
5011331164 | ||
|
|
e257c30892 | ||
|
|
029cfe6dc6 | ||
|
|
f38b8734b5 | ||
|
|
df54b92031 | ||
|
|
39acb90dbc | ||
|
|
43083d35e1 | ||
|
|
fddbfa963d | ||
|
|
94ac68e5a0 | ||
|
|
0c3373e9f0 | ||
|
|
f122bf6b6d | ||
|
|
81b300bae6 | ||
|
|
a0576df3ee | ||
|
|
e26a222755 | ||
|
|
608cdae1d8 | ||
|
|
0bb996153a | ||
|
|
1ecce85a13 | ||
|
|
644527dbfa | ||
|
|
1bd158eba0 |
167
.editorconfig
Normal file
167
.editorconfig
Normal file
@@ -0,0 +1,167 @@
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
|
||||
# Indentation and spacing
|
||||
charset = utf-8
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
tab_width = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# New line preferences
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
max_line_length = unset
|
||||
|
||||
# using directive preferences
|
||||
csharp_using_directive_placement = outside_namespace
|
||||
dotnet_diagnostic.IDE0005.severity = error
|
||||
|
||||
# Code-block preferences
|
||||
csharp_style_namespace_declarations = block_scoped
|
||||
csharp_style_prefer_method_group_conversion = true
|
||||
csharp_style_prefer_top_level_statements = false
|
||||
|
||||
# Expression-level preferences
|
||||
csharp_prefer_simple_default_expression = true
|
||||
csharp_style_inlined_variable_declaration = true
|
||||
csharp_style_unused_value_assignment_preference = discard_variable
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable
|
||||
dotnet_diagnostic.IDE0001.severity = warning
|
||||
dotnet_diagnostic.IDE0002.severity = warning
|
||||
dotnet_diagnostic.IDE0004.severity = warning
|
||||
dotnet_diagnostic.IDE0010.severity = error
|
||||
dotnet_diagnostic.IDE0051.severity = warning
|
||||
dotnet_diagnostic.IDE0052.severity = warning
|
||||
dotnet_diagnostic.IDE0072.severity = warning
|
||||
dotnet_diagnostic.IDE0080.severity = warning
|
||||
dotnet_diagnostic.IDE0100.severity = error
|
||||
dotnet_diagnostic.IDE0110.severity = error
|
||||
dotnet_diagnostic.IDE0120.severity = warning
|
||||
dotnet_diagnostic.IDE0121.severity = warning
|
||||
dotnet_diagnostic.IDE0240.severity = error
|
||||
dotnet_diagnostic.IDE0241.severity = error
|
||||
dotnet_style_coalesce_expression = true
|
||||
dotnet_style_namespace_match_folder = false
|
||||
dotnet_style_null_propagation = true
|
||||
dotnet_style_prefer_auto_properties = true
|
||||
dotnet_style_prefer_collection_expression = when_types_loosely_match
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
|
||||
dotnet_style_prefer_compound_assignment = true
|
||||
csharp_style_prefer_simple_property_accessors = true
|
||||
dotnet_style_prefer_simplified_interpolation = true
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true
|
||||
csharp_style_prefer_unbound_generic_type_in_nameof = true
|
||||
|
||||
# Field preferences
|
||||
dotnet_diagnostic.IDE0044.severity = warning
|
||||
dotnet_style_readonly_field = true
|
||||
|
||||
# Language keyword vs. framework types preferences
|
||||
dotnet_diagnostic.IDE0049.severity = error
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true
|
||||
dotnet_style_predefined_type_for_member_access = true
|
||||
|
||||
# Modifier preferences
|
||||
csharp_prefer_static_local_function = true
|
||||
csharp_style_prefer_readonly_struct = true
|
||||
dotnet_diagnostic.IDE0036.severity = warning
|
||||
dotnet_diagnostic.IDE0040.severity = error
|
||||
dotnet_diagnostic.IDE0380.severity = error
|
||||
dotnet_style_require_accessibility_modifiers = always
|
||||
|
||||
# New-line preferences
|
||||
dotnet_diagnostic.IDE2000.severity = warning
|
||||
dotnet_diagnostic.IDE2002.severity = warning
|
||||
dotnet_diagnostic.IDE2003.severity = warning
|
||||
dotnet_diagnostic.IDE2004.severity = warning
|
||||
dotnet_diagnostic.IDE2005.severity = warning
|
||||
dotnet_diagnostic.IDE2006.severity = warning
|
||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false
|
||||
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = false
|
||||
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = false
|
||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false
|
||||
dotnet_style_allow_multiple_blank_lines_experimental = false
|
||||
dotnet_style_allow_statement_immediately_after_block_experimental = false
|
||||
|
||||
# Null-checking preferences
|
||||
csharp_style_conditional_delegate_call = true
|
||||
|
||||
# Parameter preferences
|
||||
dotnet_code_quality_unused_parameters = all
|
||||
dotnet_diagnostic.IDE0280.severity = error
|
||||
|
||||
# Parentheses preferences
|
||||
dotnet_diagnostic.IDE0047.severity = warning
|
||||
dotnet_diagnostic.IDE0048.severity = warning
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
|
||||
dotnet_style_parentheses_in_other_operators = always_for_clarity
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
|
||||
|
||||
# Pattern-matching preferences
|
||||
dotnet_diagnostic.IDE0019.severity = warning
|
||||
dotnet_diagnostic.IDE0020.severity = warning
|
||||
dotnet_diagnostic.IDE0038.severity = warning
|
||||
dotnet_diagnostic.IDE0066.severity = none
|
||||
dotnet_diagnostic.IDE0083.severity = warning
|
||||
dotnet_diagnostic.IDE0260.severity = warning
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true
|
||||
csharp_style_prefer_not_pattern = true
|
||||
csharp_style_prefer_pattern_matching = true
|
||||
|
||||
# this. and Me. preferences
|
||||
dotnet_style_qualification_for_event = false
|
||||
dotnet_style_qualification_for_field = false
|
||||
dotnet_style_qualification_for_method = false
|
||||
dotnet_style_qualification_for_property = false
|
||||
|
||||
# var preferences
|
||||
csharp_style_var_for_built_in_types = false
|
||||
csharp_style_var_when_type_is_apparent = true
|
||||
|
||||
# .NET formatting options
|
||||
dotnet_separate_import_directive_groups = false
|
||||
dotnet_sort_system_directives_first = true
|
||||
|
||||
# C# formatting options
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = false
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_indent_switch_labels = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
csharp_preserve_single_line_blocks = true
|
||||
csharp_preserve_single_line_statements = true
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_around_declaration_statements = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_before_dot = false
|
||||
csharp_space_before_open_square_brackets = false
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
csharp_space_between_empty_square_brackets = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_between_square_brackets = false
|
||||
74
.github/workflows/build_and_test.yml
vendored
74
.github/workflows/build_and_test.yml
vendored
@@ -1,40 +1,48 @@
|
||||
name: Build and Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: |
|
||||
6.0.x
|
||||
8.0.x
|
||||
9.0.x
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
|
||||
- name: Run publish script
|
||||
run: ./publish-nix.sh
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.14.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: "*.nupkg,*.snupkg"
|
||||
body: 'Last built commit: ${{ github.sha }}'
|
||||
name: 'Rolling Release'
|
||||
prerelease: True
|
||||
replacesArtifacts: True
|
||||
tag: "rolling"
|
||||
updateOnlyUnreleased: True
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: |
|
||||
8.0.x
|
||||
9.0.x
|
||||
10.0.x
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
|
||||
- name: Run publish script
|
||||
run: ./publish-nix.sh
|
||||
|
||||
- name: Update rolling tag
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git tag -f rolling
|
||||
git push origin :refs/tags/rolling || true
|
||||
git push origin rolling --force
|
||||
|
||||
- name: Upload to rolling
|
||||
uses: ncipollo/release-action@v1.20.0
|
||||
with:
|
||||
allowUpdates: True
|
||||
artifacts: "*.nupkg,*.snupkg"
|
||||
body: "Last built commit: ${{ github.sha }}"
|
||||
name: "Rolling Release"
|
||||
prerelease: True
|
||||
replacesArtifacts: True
|
||||
tag: "rolling"
|
||||
updateOnlyUnreleased: True
|
||||
|
||||
34
.github/workflows/check_pr.yml
vendored
34
.github/workflows/check_pr.yml
vendored
@@ -3,21 +3,21 @@ name: Build PR
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: |
|
||||
6.0.x
|
||||
8.0.x
|
||||
9.0.x
|
||||
|
||||
- name: Build
|
||||
run: dotnet build
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v5
|
||||
with:
|
||||
dotnet-version: |
|
||||
8.0.x
|
||||
9.0.x
|
||||
10.0.x
|
||||
|
||||
- name: Build
|
||||
run: dotnet build
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using SabreTools.CommandLine.Inputs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SabreTools.CommandLine.Inputs;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.CommandLine.Test
|
||||
@@ -11,9 +13,16 @@ namespace SabreTools.CommandLine.Test
|
||||
var input1 = new FlagInput("input1", "--input1", "input1");
|
||||
var input2 = new FlagInput("input2", "--input2", "input2");
|
||||
|
||||
var feature1 = new MockFeature("feature1", "feature1", "feature1");
|
||||
var inputA = new FlagInput("inputA", "--inputA", "inputA");
|
||||
var inputB = new FlagInput("inputB", "--inputB", "inputB");
|
||||
feature1.Add(inputA);
|
||||
feature1.Add(inputB);
|
||||
|
||||
var featureSet = new CommandSet();
|
||||
featureSet.Add(input1);
|
||||
featureSet.Add(input2);
|
||||
featureSet.AddFrom(feature1);
|
||||
|
||||
var actualInput1 = featureSet["input1"];
|
||||
Assert.NotNull(actualInput1);
|
||||
@@ -25,6 +34,14 @@ namespace SabreTools.CommandLine.Test
|
||||
|
||||
var actualInput3 = featureSet["input3"];
|
||||
Assert.Null(actualInput3);
|
||||
|
||||
var actualInputA = featureSet["inputA"];
|
||||
Assert.NotNull(actualInputA);
|
||||
Assert.Equal("inputA", actualInputA.Name);
|
||||
|
||||
var actualinputB = featureSet["inputB"];
|
||||
Assert.NotNull(actualinputB);
|
||||
Assert.Equal("inputB", actualinputB.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -90,5 +107,780 @@ namespace SabreTools.CommandLine.Test
|
||||
bool actualTop3 = featureSet.IsTopLevel("input3");
|
||||
Assert.False(actualTop3);
|
||||
}
|
||||
|
||||
#region GetBoolean
|
||||
|
||||
[Fact]
|
||||
public void GetBoolean_InvalidKey_DefaultValue()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new BooleanInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
bool actual = commandSet.GetBoolean("c");
|
||||
Assert.False(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetBoolean_Exists_WrongType_Throws()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
Assert.Throws<ArgumentException>(() => _ = commandSet.GetBoolean("b"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetBoolean_Exists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new BooleanInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
int index = 0;
|
||||
child.ProcessInput(["b", "true"], ref index);
|
||||
|
||||
bool actual = commandSet.GetBoolean("b");
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetBoolean_NestedExists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
var subChild = new BooleanInput("c", "c", "c");
|
||||
child.Add(subChild);
|
||||
|
||||
int index = 0;
|
||||
subChild.ProcessInput(["c", "true"], ref index);
|
||||
|
||||
bool actual = commandSet.GetBoolean("c");
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetFeature
|
||||
|
||||
[Fact]
|
||||
public void GetFeature_InvalidKey_Null()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockFeature("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
Feature? actual = commandSet.GetFeature("c");
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFeature_Exists_WrongType_Throws()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
Assert.Throws<ArgumentException>(() => _ = commandSet.GetFeature("b"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFeature_Exists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockFeature("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
int index = 0;
|
||||
child.ProcessInput(["b"], ref index);
|
||||
|
||||
Feature? actual = commandSet.GetFeature("b");
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal("b", actual.Name);
|
||||
Assert.True(actual.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFeature_NestedExists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
var subChild = new MockFeature("c", "c", "c");
|
||||
child.Add(subChild);
|
||||
|
||||
int index = 0;
|
||||
subChild.ProcessInput(["c"], ref index);
|
||||
|
||||
Feature? actual = commandSet.GetFeature("c");
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal("c", actual.Name);
|
||||
Assert.True(actual.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetInt8
|
||||
|
||||
[Fact]
|
||||
public void GetInt8_InvalidKey_DefaultValue()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new Int8Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
sbyte actual = commandSet.GetInt8("c");
|
||||
Assert.Equal(sbyte.MinValue, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt8_Exists_WrongType_Throws()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
Assert.Throws<ArgumentException>(() => _ = commandSet.GetInt8("b"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt8_Exists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new Int8Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
int index = 0;
|
||||
child.ProcessInput(["b", "5"], ref index);
|
||||
|
||||
sbyte actual = commandSet.GetInt8("b");
|
||||
Assert.Equal(5, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt8_NestedExists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
var subChild = new Int8Input("c", "c", "c");
|
||||
child.Add(subChild);
|
||||
|
||||
int index = 0;
|
||||
subChild.ProcessInput(["c", "5"], ref index);
|
||||
|
||||
sbyte actual = commandSet.GetInt8("c");
|
||||
Assert.Equal(5, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetInt16
|
||||
|
||||
[Fact]
|
||||
public void GetInt16_InvalidKey_DefaultValue()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new Int16Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
short actual = commandSet.GetInt16("c");
|
||||
Assert.Equal(short.MinValue, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt16_Exists_WrongType_Throws()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
Assert.Throws<ArgumentException>(() => _ = commandSet.GetInt16("b"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt16_Exists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new Int16Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
int index = 0;
|
||||
child.ProcessInput(["b", "5"], ref index);
|
||||
|
||||
short actual = commandSet.GetInt16("b");
|
||||
Assert.Equal(5, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt16_NestedExists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
var subChild = new Int16Input("c", "c", "c");
|
||||
child.Add(subChild);
|
||||
|
||||
int index = 0;
|
||||
subChild.ProcessInput(["c", "5"], ref index);
|
||||
|
||||
short actual = commandSet.GetInt16("c");
|
||||
Assert.Equal(5, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetInt32
|
||||
|
||||
[Fact]
|
||||
public void GetInt32_InvalidKey_DefaultValue()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new Int32Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
int actual = commandSet.GetInt32("c");
|
||||
Assert.Equal(int.MinValue, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt32_Exists_WrongType_Throws()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
Assert.Throws<ArgumentException>(() => _ = commandSet.GetInt32("b"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt32_Exists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new Int32Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
int index = 0;
|
||||
child.ProcessInput(["b", "5"], ref index);
|
||||
|
||||
int actual = commandSet.GetInt32("b");
|
||||
Assert.Equal(5, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt32_NestedExists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
var subChild = new Int32Input("c", "c", "c");
|
||||
child.Add(subChild);
|
||||
|
||||
int index = 0;
|
||||
subChild.ProcessInput(["c", "5"], ref index);
|
||||
|
||||
int actual = commandSet.GetInt32("c");
|
||||
Assert.Equal(5, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetInt64
|
||||
|
||||
[Fact]
|
||||
public void GetInt64_InvalidKey_DefaultValue()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new Int64Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
long actual = commandSet.GetInt64("c");
|
||||
Assert.Equal(long.MinValue, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt64_Exists_WrongType_Throws()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
Assert.Throws<ArgumentException>(() => _ = commandSet.GetInt64("b"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt64_Exists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new Int64Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
int index = 0;
|
||||
child.ProcessInput(["b", "5"], ref index);
|
||||
|
||||
long actual = commandSet.GetInt64("b");
|
||||
Assert.Equal(5, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetInt64_NestedExists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
var subChild = new Int64Input("c", "c", "c");
|
||||
child.Add(subChild);
|
||||
|
||||
int index = 0;
|
||||
subChild.ProcessInput(["c", "5"], ref index);
|
||||
|
||||
long actual = commandSet.GetInt64("c");
|
||||
Assert.Equal(5, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetString
|
||||
|
||||
[Fact]
|
||||
public void GetString_InvalidKey_DefaultValue()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new StringInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
string? actual = commandSet.GetString("c");
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetString_Exists_WrongType_Throws()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
Assert.Throws<ArgumentException>(() => _ = commandSet.GetString("b"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetString_Exists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new StringInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
int index = 0;
|
||||
child.ProcessInput(["b", "value"], ref index);
|
||||
|
||||
string? actual = commandSet.GetString("b");
|
||||
Assert.Equal("value", actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetString_NestedExists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
var subChild = new StringInput("c", "c", "c");
|
||||
child.Add(subChild);
|
||||
|
||||
int index = 0;
|
||||
subChild.ProcessInput(["c", "value"], ref index);
|
||||
|
||||
string? actual = commandSet.GetString("c");
|
||||
Assert.Equal("value", actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetStringList
|
||||
|
||||
[Fact]
|
||||
public void GetStringList_InvalidKey_DefaultValue()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new StringListInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
List<string> actual = commandSet.GetStringList("c");
|
||||
Assert.Empty(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStringList_Exists_WrongType_Throws()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
Assert.Throws<ArgumentException>(() => _ = commandSet.GetStringList("b"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStringList_Exists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new StringListInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
int index = 0;
|
||||
child.ProcessInput(["b", "value"], ref index);
|
||||
|
||||
List<string> actual = commandSet.GetStringList("b");
|
||||
string value = Assert.Single(actual);
|
||||
Assert.Equal("value", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetStringList_NestedExists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
var subChild = new StringListInput("c", "c", "c");
|
||||
child.Add(subChild);
|
||||
|
||||
int index = 0;
|
||||
subChild.ProcessInput(["c", "value"], ref index);
|
||||
|
||||
List<string> actual = commandSet.GetStringList("c");
|
||||
string value = Assert.Single(actual);
|
||||
Assert.Equal("value", value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetUInt8
|
||||
|
||||
[Fact]
|
||||
public void GetUInt8_InvalidKey_DefaultValue()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new UInt8Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
byte actual = commandSet.GetUInt8("c");
|
||||
Assert.Equal(byte.MinValue, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetUInt8_Exists_WrongType_Throws()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
Assert.Throws<ArgumentException>(() => _ = commandSet.GetUInt8("b"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetUInt8_Exists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new UInt8Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
int index = 0;
|
||||
child.ProcessInput(["b", "5"], ref index);
|
||||
|
||||
byte actual = commandSet.GetUInt8("b");
|
||||
Assert.Equal(5, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetUInt8_NestedExists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
var subChild = new UInt8Input("c", "c", "c");
|
||||
child.Add(subChild);
|
||||
|
||||
int index = 0;
|
||||
subChild.ProcessInput(["c", "5"], ref index);
|
||||
|
||||
byte actual = commandSet.GetUInt8("c");
|
||||
Assert.Equal(5, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetUInt16
|
||||
|
||||
[Fact]
|
||||
public void GetUInt16_InvalidKey_DefaultValue()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new UInt16Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
ushort actual = commandSet.GetUInt16("c");
|
||||
Assert.Equal(ushort.MinValue, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetUInt16_Exists_WrongType_Throws()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
Assert.Throws<ArgumentException>(() => _ = commandSet.GetUInt16("b"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetUInt16_Exists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new UInt16Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
int index = 0;
|
||||
child.ProcessInput(["b", "5"], ref index);
|
||||
|
||||
ushort actual = commandSet.GetUInt16("b");
|
||||
Assert.Equal(5, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetUInt16_NestedExists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
var subChild = new UInt16Input("c", "c", "c");
|
||||
child.Add(subChild);
|
||||
|
||||
int index = 0;
|
||||
subChild.ProcessInput(["c", "5"], ref index);
|
||||
|
||||
ushort actual = commandSet.GetUInt16("c");
|
||||
Assert.Equal(5, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetUInt32
|
||||
|
||||
[Fact]
|
||||
public void GetUInt32_InvalidKey_DefaultValue()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new UInt32Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
uint actual = commandSet.GetUInt32("c");
|
||||
Assert.Equal(uint.MinValue, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetUInt32_Exists_WrongType_Throws()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
Assert.Throws<ArgumentException>(() => _ = commandSet.GetUInt32("b"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetUInt32_Exists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new UInt32Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
int index = 0;
|
||||
child.ProcessInput(["b", "5"], ref index);
|
||||
|
||||
uint actual = commandSet.GetUInt32("b");
|
||||
Assert.Equal(5u, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetUInt32_NestedExists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
var subChild = new UInt32Input("c", "c", "c");
|
||||
child.Add(subChild);
|
||||
|
||||
int index = 0;
|
||||
subChild.ProcessInput(["c", "5"], ref index);
|
||||
|
||||
uint actual = commandSet.GetUInt32("c");
|
||||
Assert.Equal(5u, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetUInt64
|
||||
|
||||
[Fact]
|
||||
public void GetUInt64_InvalidKey_DefaultValue()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new UInt64Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
ulong actual = commandSet.GetUInt64("c");
|
||||
Assert.Equal(ulong.MinValue, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetUInt64_Exists_WrongType_Throws()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
Assert.Throws<ArgumentException>(() => _ = commandSet.GetUInt64("b"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetUInt64_Exists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new UInt64Input("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
|
||||
int index = 0;
|
||||
child.ProcessInput(["b", "5"], ref index);
|
||||
|
||||
ulong actual = commandSet.GetUInt64("b");
|
||||
Assert.Equal(5u, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetUInt64_NestedExists_Returns()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
commandSet.Add(child);
|
||||
var subChild = new UInt64Input("c", "c", "c");
|
||||
child.Add(subChild);
|
||||
|
||||
int index = 0;
|
||||
subChild.ProcessInput(["c", "5"], ref index);
|
||||
|
||||
ulong actual = commandSet.GetUInt64("c");
|
||||
Assert.Equal(5u, actual);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ProcessArgs
|
||||
|
||||
[Fact]
|
||||
public void ProcessArgs_EmptyArgs_Success()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
|
||||
string[] args = [];
|
||||
|
||||
bool actual = commandSet.ProcessArgs(args);
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessArgs_ValidArgs_Success()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
Feature feature = new MockFeature("a", "a", "a");
|
||||
feature.Add(new FlagInput("b", "b", "b"));
|
||||
feature.Add(new FlagInput("c", "c", "c"));
|
||||
commandSet.Add(feature);
|
||||
|
||||
string[] args = ["a", "b", "c"];
|
||||
|
||||
bool actual = commandSet.ProcessArgs(args);
|
||||
Assert.True(actual);
|
||||
Assert.Empty(feature.Inputs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessArgs_InvalidArg_AddedAsGeneric()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
Feature feature = new MockFeature("a", "a", "a");
|
||||
feature.Add(new FlagInput("b", "b", "b"));
|
||||
feature.Add(new FlagInput("d", "d", "d"));
|
||||
commandSet.Add(feature);
|
||||
|
||||
string[] args = ["a", "b", "c"];
|
||||
|
||||
bool actual = commandSet.ProcessArgs(args);
|
||||
Assert.True(actual);
|
||||
string input = Assert.Single(feature.Inputs);
|
||||
Assert.Equal("c", input);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessArgs_NestedArgs_Success()
|
||||
{
|
||||
var commandSet = new CommandSet();
|
||||
Feature feature = new MockFeature("a", "a", "a");
|
||||
var sub = new FlagInput("b", "b", "b");
|
||||
sub.Add(new FlagInput("c", "c", "c"));
|
||||
feature.Add(sub);
|
||||
commandSet.Add(feature);
|
||||
|
||||
string[] args = ["a", "b", "c"];
|
||||
|
||||
bool actual = commandSet.ProcessArgs(args);
|
||||
Assert.True(actual);
|
||||
Assert.Empty(feature.Inputs);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Mock Feature implementation for testing
|
||||
/// </summary>
|
||||
private class MockFeature : Feature
|
||||
{
|
||||
public MockFeature(string name, string flag, string description, string? detailed = null)
|
||||
: base(name, flag, description, detailed)
|
||||
{
|
||||
}
|
||||
|
||||
public MockFeature(string name, string[] flags, string description, string? detailed = null)
|
||||
: base(name, flags, description, detailed)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Execute() => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool VerifyInputs() => true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mock UserInput implementation for testing
|
||||
/// </summary>
|
||||
private class MockUserInput : UserInput<object?>
|
||||
{
|
||||
public MockUserInput(string name, string flag, string description, string? detailed = null)
|
||||
: base(name, flag, description, detailed)
|
||||
{
|
||||
}
|
||||
|
||||
public MockUserInput(string name, string[] flags, string description, string? detailed = null)
|
||||
: base(name, flags, description, detailed)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool ProcessInput(string[] args, ref int index) => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string FormatFlags() => string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,65 @@ namespace SabreTools.CommandLine.Test.Inputs
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetFeature
|
||||
|
||||
[Fact]
|
||||
public void GetFeature_InvalidKey_Null()
|
||||
{
|
||||
UserInput userInput = new MockUserInput("a", "a", "a");
|
||||
var child = new MockFeature("b", "b", "b");
|
||||
userInput.Add(child);
|
||||
|
||||
Feature? actual = userInput.GetFeature("c");
|
||||
Assert.Null(actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFeature_Exists_WrongType_Throws()
|
||||
{
|
||||
UserInput userInput = new MockUserInput("a", "a", "a");
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
userInput.Add(child);
|
||||
|
||||
Assert.Throws<ArgumentException>(() => _ = userInput.GetFeature("b"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFeature_Exists_Returns()
|
||||
{
|
||||
UserInput userInput = new MockUserInput("a", "a", "a");
|
||||
var child = new MockFeature("b", "b", "b");
|
||||
userInput.Add(child);
|
||||
|
||||
int index = 0;
|
||||
child.ProcessInput(["b"], ref index);
|
||||
|
||||
Feature? actual = userInput.GetFeature("b");
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal("b", actual.Name);
|
||||
Assert.True(actual.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFeature_NestedExists_Returns()
|
||||
{
|
||||
UserInput userInput = new MockUserInput("a", "a", "a");
|
||||
var child = new MockUserInput("b", "b", "b");
|
||||
userInput.Add(child);
|
||||
var subChild = new MockFeature("c", "c", "c");
|
||||
child.Add(subChild);
|
||||
|
||||
int index = 0;
|
||||
subChild.ProcessInput(["c"], ref index);
|
||||
|
||||
Feature? actual = userInput.GetFeature("c");
|
||||
Assert.NotNull(actual);
|
||||
Assert.Equal("c", actual.Name);
|
||||
Assert.True(actual.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetInt8
|
||||
|
||||
[Fact]
|
||||
@@ -666,6 +725,28 @@ namespace SabreTools.CommandLine.Test.Inputs
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Mock Feature implementation for testing
|
||||
/// </summary>
|
||||
private class MockFeature : Feature
|
||||
{
|
||||
public MockFeature(string name, string flag, string description, string? detailed = null)
|
||||
: base(name, flag, description, detailed)
|
||||
{
|
||||
}
|
||||
|
||||
public MockFeature(string name, string[] flags, string description, string? detailed = null)
|
||||
: base(name, flags, description, detailed)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Execute() => true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool VerifyInputs() => true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mock UserInput implementation for testing
|
||||
/// </summary>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
|
||||
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
@@ -16,7 +16,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SabreTools.CommandLine.Features;
|
||||
using SabreTools.CommandLine.Inputs;
|
||||
|
||||
namespace SabreTools.CommandLine
|
||||
@@ -39,6 +40,41 @@ namespace SabreTools.CommandLine
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Custom help text to print instead of the automatically
|
||||
/// generated generic help
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This only replaces the automatically generated help
|
||||
/// for <see cref="OutputGenericHelp"/>. It does not impact
|
||||
/// either <see cref="OutputAllHelp"/> or <see cref="OutputFeatureHelp"/>.
|
||||
/// </remarks>
|
||||
public string? CustomHelp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Feature that represents the default functionality
|
||||
/// for a command set
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It is recommended to use this in applications that
|
||||
/// do not need multiple distinct functional modes.
|
||||
///
|
||||
/// When printing help text, the flags and description
|
||||
/// of this feature will be omitted, instead printing
|
||||
/// the children of the feature directly at the
|
||||
/// top level.
|
||||
///
|
||||
/// If the default feature is included as a normal
|
||||
/// top-level input for the command set, then the flags
|
||||
/// will be printed twice - once under the feature
|
||||
/// itself and once at the top level.
|
||||
/// </remarks>
|
||||
public Feature? DefaultFeature { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
@@ -46,6 +82,15 @@ namespace SabreTools.CommandLine
|
||||
/// </summary>
|
||||
public CommandSet() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new CommandSet with a printable header
|
||||
/// </summary>
|
||||
/// <param name="header">Custom commandline header to be printed when outputting help</param>
|
||||
public CommandSet(string header)
|
||||
{
|
||||
_header.Add(header);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new CommandSet with a printable header
|
||||
/// </summary>
|
||||
@@ -55,6 +100,17 @@ namespace SabreTools.CommandLine
|
||||
_header.AddRange(header);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new CommandSet with a printable header
|
||||
/// </summary>
|
||||
/// <param name="header">Custom commandline header to be printed when outputting help</param>
|
||||
/// <param name="footer">Custom commandline footer to be printed when outputting help</param>
|
||||
public CommandSet(string header, string footer)
|
||||
{
|
||||
_header.Add(header);
|
||||
_footer.Add(footer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new CommandSet with a printable header
|
||||
/// </summary>
|
||||
@@ -99,6 +155,565 @@ namespace SabreTools.CommandLine
|
||||
public void Add(UserInput input)
|
||||
=> _inputs.Add(input.Name, input);
|
||||
|
||||
/// <summary>
|
||||
/// Add all children from an input to the set
|
||||
/// </summary>
|
||||
/// <param name="input">UserInput object to retrieve children from</param>
|
||||
/// <remarks>
|
||||
/// This should only be used in situations where an input is defined
|
||||
/// but not used within the context of the command set directly.
|
||||
///
|
||||
/// This is helpful for when there are applications with default functionality
|
||||
/// that need to be able to expose both defined features as well as
|
||||
/// the default functionality in help text.
|
||||
///
|
||||
/// If there is any overlap between existing names and the names from
|
||||
/// any of the children, this operation will overwrite them.
|
||||
/// </reamrks>
|
||||
public void AddFrom(UserInput input)
|
||||
{
|
||||
foreach (var kvp in input.Children)
|
||||
{
|
||||
_inputs.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Children
|
||||
|
||||
/// <summary>
|
||||
/// Get a boolean value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>The value if found, the default value otherwise</returns>
|
||||
public bool GetBoolean(string key, bool defaultValue = false)
|
||||
{
|
||||
if (TryGetBoolean(key, out bool value, defaultValue))
|
||||
return value;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a Feature value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <returns>The value if found, null otherwise</returns>
|
||||
public Feature? GetFeature(string key)
|
||||
{
|
||||
if (TryGetFeature(key, out Feature? value))
|
||||
return value;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an Int8 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>The value if found, the default value otherwise</returns>
|
||||
public sbyte GetInt8(string key, sbyte defaultValue = sbyte.MinValue)
|
||||
{
|
||||
if (TryGetInt8(key, out sbyte value, defaultValue))
|
||||
return value;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an Int16 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>The value if found, the default value otherwise</returns>
|
||||
public short GetInt16(string key, short defaultValue = short.MinValue)
|
||||
{
|
||||
if (TryGetInt16(key, out short value, defaultValue))
|
||||
return value;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an Int32 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>The value if found, the default value otherwise</returns>
|
||||
public int GetInt32(string key, int defaultValue = int.MinValue)
|
||||
{
|
||||
if (TryGetInt32(key, out int value, defaultValue))
|
||||
return value;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an Int64 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>The value if found, the default value otherwise</returns>
|
||||
public long GetInt64(string key, long defaultValue = long.MinValue)
|
||||
{
|
||||
if (TryGetInt64(key, out long value, defaultValue))
|
||||
return value;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a string value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>The value if found, the default value otherwise</returns>
|
||||
public string? GetString(string key, string? defaultValue = null)
|
||||
{
|
||||
if (TryGetString(key, out string? value, defaultValue))
|
||||
return value;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a string list value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>The value if found, the default value otherwise</returns>
|
||||
public List<string> GetStringList(string key)
|
||||
{
|
||||
if (TryGetStringList(key, out var value))
|
||||
return value;
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a UInt8 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>The value if found, the default value otherwise</returns>
|
||||
public byte GetUInt8(string key, byte defaultValue = byte.MinValue)
|
||||
{
|
||||
if (TryGetUInt8(key, out byte value, defaultValue))
|
||||
return value;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a UInt16 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>The value if found, the default value otherwise</returns>
|
||||
public ushort GetUInt16(string key, ushort defaultValue = ushort.MinValue)
|
||||
{
|
||||
if (TryGetUInt16(key, out ushort value, defaultValue))
|
||||
return value;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a UInt32 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>The value if found, the default value otherwise</returns>
|
||||
public uint GetUInt32(string key, uint defaultValue = uint.MinValue)
|
||||
{
|
||||
if (TryGetUInt32(key, out uint value, defaultValue))
|
||||
return value;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a UInt64 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>The value if found, the default value otherwise</returns>
|
||||
public ulong GetUInt64(string key, ulong defaultValue = ulong.MinValue)
|
||||
{
|
||||
if (TryGetUInt64(key, out ulong value, defaultValue))
|
||||
return value;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a boolean value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="value">Value that was found, default value otherwise</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>True if the value was found, false otherwise</returns>
|
||||
public bool TryGetBoolean(string key, out bool value, bool defaultValue = false)
|
||||
{
|
||||
// Try to check immediate children
|
||||
if (_inputs.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is BooleanInput b)
|
||||
{
|
||||
value = b.Value ?? defaultValue;
|
||||
return true;
|
||||
}
|
||||
else if (input is FlagInput f)
|
||||
{
|
||||
value = f.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new ArgumentException("Input is not a bool");
|
||||
}
|
||||
|
||||
// Check all children recursively
|
||||
foreach (var child in _inputs.Values)
|
||||
{
|
||||
if (child.TryGetBoolean(key, out value, defaultValue))
|
||||
return true;
|
||||
}
|
||||
|
||||
value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a Feature value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="value">Value that was found, default value otherwise</param>
|
||||
/// <returns>True if the value was found, false otherwise</returns>
|
||||
public bool TryGetFeature(string key, out Feature? value)
|
||||
{
|
||||
// Try to check immediate children
|
||||
if (_inputs.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not Feature i)
|
||||
throw new ArgumentException("Input is not a Feature");
|
||||
|
||||
value = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check all children recursively
|
||||
foreach (var child in _inputs.Values)
|
||||
{
|
||||
if (child.TryGetFeature(key, out value))
|
||||
return true;
|
||||
}
|
||||
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an Int8 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="value">Value that was found, default value otherwise</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>True if the value was found, false otherwise</returns>
|
||||
public bool TryGetInt8(string key, out sbyte value, sbyte defaultValue = sbyte.MinValue)
|
||||
{
|
||||
// Try to check immediate children
|
||||
if (_inputs.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not Int8Input i)
|
||||
throw new ArgumentException("Input is not an sbyte");
|
||||
|
||||
value = i.Value ?? defaultValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check all children recursively
|
||||
foreach (var child in _inputs.Values)
|
||||
{
|
||||
if (child.TryGetInt8(key, out value, defaultValue))
|
||||
return true;
|
||||
}
|
||||
|
||||
value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an Int16 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="value">Value that was found, default value otherwise</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>True if the value was found, false otherwise</returns>
|
||||
public bool TryGetInt16(string key, out short value, short defaultValue = short.MinValue)
|
||||
{
|
||||
// Try to check immediate children
|
||||
if (_inputs.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not Int16Input i)
|
||||
throw new ArgumentException("Input is not a short");
|
||||
|
||||
value = i.Value ?? defaultValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check all children recursively
|
||||
foreach (var child in _inputs.Values)
|
||||
{
|
||||
if (child.TryGetInt16(key, out value, defaultValue))
|
||||
return true;
|
||||
}
|
||||
|
||||
value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an Int32 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="value">Value that was found, default value otherwise</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>True if the value was found, false otherwise</returns>
|
||||
public bool TryGetInt32(string key, out int value, int defaultValue = int.MinValue)
|
||||
{
|
||||
// Try to check immediate children
|
||||
if (_inputs.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not Int32Input i)
|
||||
throw new ArgumentException("Input is not an int");
|
||||
|
||||
value = i.Value ?? defaultValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check all children recursively
|
||||
foreach (var child in _inputs.Values)
|
||||
{
|
||||
if (child.TryGetInt32(key, out value, defaultValue))
|
||||
return true;
|
||||
}
|
||||
|
||||
value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an Int64 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="value">Value that was found, default value otherwise</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>True if the value was found, false otherwise</returns>
|
||||
public bool TryGetInt64(string key, out long value, long defaultValue = long.MinValue)
|
||||
{
|
||||
// Try to check immediate children
|
||||
if (_inputs.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not Int64Input l)
|
||||
throw new ArgumentException("Input is not a long");
|
||||
|
||||
value = l.Value ?? defaultValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check all children recursively
|
||||
foreach (var child in _inputs.Values)
|
||||
{
|
||||
if (child.TryGetInt64(key, out value, defaultValue))
|
||||
return true;
|
||||
}
|
||||
|
||||
value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a string value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="value">Value that was found, default value otherwise</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>True if the value was found, false otherwise</returns>
|
||||
public bool TryGetString(string key, out string? value, string? defaultValue = null)
|
||||
{
|
||||
// Try to check immediate children
|
||||
if (_inputs.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not StringInput s)
|
||||
throw new ArgumentException("Input is not a string");
|
||||
|
||||
value = s.Value ?? defaultValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check all children recursively
|
||||
foreach (var child in _inputs.Values)
|
||||
{
|
||||
if (child.TryGetString(key, out value, defaultValue))
|
||||
return true;
|
||||
}
|
||||
|
||||
value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a string list value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="value">Value that was found, default value otherwise</param>
|
||||
/// <returns>True if the value was found, false otherwise</returns>
|
||||
public bool TryGetStringList(string key, out List<string> value)
|
||||
{
|
||||
// Try to check immediate children
|
||||
if (_inputs.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not StringListInput l)
|
||||
throw new ArgumentException("Input is not a list");
|
||||
|
||||
value = l.Value ?? [];
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check all children recursively
|
||||
foreach (var child in _inputs.Values)
|
||||
{
|
||||
if (child.TryGetStringList(key, out value))
|
||||
return true;
|
||||
}
|
||||
|
||||
value = [];
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a UInt8 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="value">Value that was found, default value otherwise</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>True if the value was found, false otherwise</returns>
|
||||
public bool TryGetUInt8(string key, out byte value, byte defaultValue = byte.MinValue)
|
||||
{
|
||||
// Try to check immediate children
|
||||
if (_inputs.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not UInt8Input i)
|
||||
throw new ArgumentException("Input is not an byte");
|
||||
|
||||
value = i.Value ?? defaultValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check all children recursively
|
||||
foreach (var child in _inputs.Values)
|
||||
{
|
||||
if (child.TryGetUInt8(key, out value, defaultValue))
|
||||
return true;
|
||||
}
|
||||
|
||||
value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a UInt16 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="value">Value that was found, default value otherwise</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>True if the value was found, false otherwise</returns>
|
||||
public bool TryGetUInt16(string key, out ushort value, ushort defaultValue = ushort.MinValue)
|
||||
{
|
||||
// Try to check immediate children
|
||||
if (_inputs.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not UInt16Input i)
|
||||
throw new ArgumentException("Input is not a ushort");
|
||||
|
||||
value = i.Value ?? defaultValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check all children recursively
|
||||
foreach (var child in _inputs.Values)
|
||||
{
|
||||
if (child.TryGetUInt16(key, out value, defaultValue))
|
||||
return true;
|
||||
}
|
||||
|
||||
value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a UInt32 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="value">Value that was found, default value otherwise</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>True if the value was found, false otherwise</returns>
|
||||
public bool TryGetUInt32(string key, out uint value, uint defaultValue = uint.MinValue)
|
||||
{
|
||||
// Try to check immediate children
|
||||
if (_inputs.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not UInt32Input i)
|
||||
throw new ArgumentException("Input is not an uint");
|
||||
|
||||
value = i.Value ?? defaultValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check all children recursively
|
||||
foreach (var child in _inputs.Values)
|
||||
{
|
||||
if (child.TryGetUInt32(key, out value, defaultValue))
|
||||
return true;
|
||||
}
|
||||
|
||||
value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a UInt64 value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="value">Value that was found, default value otherwise</param>
|
||||
/// <param name="defaultValue">Optional default value if not found</param>
|
||||
/// <returns>True if the value was found, false otherwise</returns>
|
||||
public bool TryGetUInt64(string key, out ulong value, ulong defaultValue = ulong.MinValue)
|
||||
{
|
||||
// Try to check immediate children
|
||||
if (_inputs.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not UInt64Input l)
|
||||
throw new ArgumentException("Input is not a ulong");
|
||||
|
||||
value = l.Value ?? defaultValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check all children recursively
|
||||
foreach (var child in _inputs.Values)
|
||||
{
|
||||
if (child.TryGetUInt64(key, out value, defaultValue))
|
||||
return true;
|
||||
}
|
||||
|
||||
value = defaultValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Inputs
|
||||
@@ -163,7 +778,8 @@ namespace SabreTools.CommandLine
|
||||
/// <summary>
|
||||
/// Output top-level features only
|
||||
/// </summary>
|
||||
public void OutputGenericHelp()
|
||||
/// <param name="detailed">True if the detailed descriptions should be formatted and output, false otherwise</param>
|
||||
public void OutputGenericHelp(bool detailed = false)
|
||||
{
|
||||
// Start building the output list
|
||||
List<string> output = [];
|
||||
@@ -172,13 +788,34 @@ namespace SabreTools.CommandLine
|
||||
if (_header.Count > 0)
|
||||
output.AddRange(_header);
|
||||
|
||||
// Now append all available top-level flags
|
||||
output.Add("Available options:");
|
||||
foreach (var input in _inputs.Values)
|
||||
// If custom help text is defined
|
||||
if (CustomHelp is not null)
|
||||
{
|
||||
var outputs = input.Format(pre: 2, midpoint: 30);
|
||||
if (outputs != null)
|
||||
output.AddRange(outputs);
|
||||
string customHelp = CustomHelp.Replace("\r\n", "\n");
|
||||
string[] customLines = customHelp.Split('\n');
|
||||
output.AddRange(customLines);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Append all available top-level flags
|
||||
output.Add("Available options:");
|
||||
foreach (var input in _inputs.Values)
|
||||
{
|
||||
var outputs = input.Format(pre: 2, midpoint: 30, detailed);
|
||||
if (outputs is not null)
|
||||
output.AddRange(outputs);
|
||||
}
|
||||
|
||||
// If there is a default feature
|
||||
if (DefaultFeature is not null)
|
||||
{
|
||||
foreach (var input in DefaultFeature.Children)
|
||||
{
|
||||
var outputs = input.Value.Format(pre: 2, midpoint: 30, detailed);
|
||||
if (outputs is not null)
|
||||
output.AddRange(outputs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Append the footer, if needed
|
||||
@@ -192,7 +829,8 @@ namespace SabreTools.CommandLine
|
||||
/// <summary>
|
||||
/// Output all features recursively
|
||||
/// </summary>
|
||||
public void OutputAllHelp()
|
||||
/// <param name="detailed">True if the detailed descriptions should be formatted and output, false otherwise</param>
|
||||
public void OutputAllHelp(bool detailed = false)
|
||||
{
|
||||
// Start building the output list
|
||||
List<string> output = [];
|
||||
@@ -201,15 +839,26 @@ namespace SabreTools.CommandLine
|
||||
if (_header.Count > 0)
|
||||
output.AddRange(_header);
|
||||
|
||||
// Now append all available flags recursively
|
||||
// Append all available flags recursively
|
||||
output.Add("Available options:");
|
||||
foreach (var input in _inputs.Values)
|
||||
{
|
||||
var outputs = input.FormatRecursive(pre: 2, midpoint: 30, detailed: true);
|
||||
if (outputs != null)
|
||||
var outputs = input.FormatRecursive(pre: 2, midpoint: 30, detailed);
|
||||
if (outputs is not null)
|
||||
output.AddRange(outputs);
|
||||
}
|
||||
|
||||
// If there is a default feature
|
||||
if (DefaultFeature is not null)
|
||||
{
|
||||
foreach (var input in DefaultFeature.Children)
|
||||
{
|
||||
var outputs = input.Value.Format(pre: 2, midpoint: 30, detailed);
|
||||
if (outputs is not null)
|
||||
output.AddRange(outputs);
|
||||
}
|
||||
}
|
||||
|
||||
// Append the footer, if needed
|
||||
if (_footer.Count > 0)
|
||||
output.AddRange(_footer);
|
||||
@@ -313,5 +962,71 @@ namespace SabreTools.CommandLine
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Processing
|
||||
|
||||
/// <summary>
|
||||
/// Process args list with default handling
|
||||
/// </summary>
|
||||
/// <param name="args">Set of arguments to process</param>
|
||||
/// <returns>True if all arguments were processed correctly, false otherwise</returns>
|
||||
/// <remarks>
|
||||
/// This default processing implementation assumes a few key points:
|
||||
/// - Top-level items are all <see cref="Feature"/>
|
||||
/// - There is only top-level item allowed at a time
|
||||
/// - The first argument is always the <see cref="Feature"/> flag
|
||||
/// </remarks>
|
||||
public bool ProcessArgs(string[] args)
|
||||
{
|
||||
// If there's no arguments, show help
|
||||
if (args.Length == 0)
|
||||
{
|
||||
OutputAllHelp();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the first argument as a feature flag
|
||||
string featureName = args[0];
|
||||
|
||||
// Get the associated feature
|
||||
var topLevel = GetTopLevel(featureName);
|
||||
if (topLevel is null || topLevel is not Feature feature)
|
||||
{
|
||||
Console.WriteLine($"'{featureName}' is not valid feature flag");
|
||||
OutputFeatureHelp(featureName);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle default help functionality
|
||||
if (topLevel is Help helpFeature)
|
||||
{
|
||||
helpFeature.ProcessArgs(args, 0, this);
|
||||
return true;
|
||||
}
|
||||
else if (topLevel is HelpExtended helpExtFeature)
|
||||
{
|
||||
helpExtFeature.ProcessArgs(args, 0, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now verify that all other flags are valid
|
||||
if (!feature.ProcessArgs(args, 1))
|
||||
{
|
||||
OutputFeatureHelp(topLevel.Name);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If inputs are required
|
||||
if (feature.RequiresInputs && !feature.VerifyInputs())
|
||||
{
|
||||
OutputFeatureHelp(topLevel.Name);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now execute the current feature
|
||||
return feature.Execute();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace SabreTools.CommandLine.Features
|
||||
try
|
||||
{
|
||||
var assembly = Assembly.GetEntryAssembly();
|
||||
if (assembly == null)
|
||||
if (assembly is null)
|
||||
return null;
|
||||
|
||||
var assemblyVersion = Attribute.GetCustomAttribute(assembly, typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute;
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Text;
|
||||
namespace SabreTools.CommandLine.Inputs
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a user input bounded to the range of <see cref="bool"/>
|
||||
/// Represents a user input bounded to the range of <see cref="bool"/>
|
||||
/// </summary>
|
||||
public class BooleanInput : UserInput<bool?>
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Text;
|
||||
namespace SabreTools.CommandLine.Inputs
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a user input bounded to the range of <see cref="short"/>
|
||||
/// Represents a user input bounded to the range of <see cref="short"/>
|
||||
/// </summary>
|
||||
public class Int16Input : UserInput<short?>
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Text;
|
||||
namespace SabreTools.CommandLine.Inputs
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a user input bounded to the range of <see cref="int"/>
|
||||
/// Represents a user input bounded to the range of <see cref="int"/>
|
||||
/// </summary>
|
||||
public class Int32Input : UserInput<int?>
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Text;
|
||||
namespace SabreTools.CommandLine.Inputs
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a user input bounded to the range of <see cref="long"/>
|
||||
/// Represents a user input bounded to the range of <see cref="long"/>
|
||||
/// </summary>
|
||||
public class Int64Input : UserInput<long?>
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Text;
|
||||
namespace SabreTools.CommandLine.Inputs
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a user input bounded to the range of <see cref="sbyte"/>
|
||||
/// Represents a user input bounded to the range of <see cref="sbyte"/>
|
||||
/// </summary>
|
||||
public class Int8Input : UserInput<sbyte?>
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Text;
|
||||
namespace SabreTools.CommandLine.Inputs
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a user input bounded to the range of <see cref="ushort"/>
|
||||
/// Represents a user input bounded to the range of <see cref="ushort"/>
|
||||
/// </summary>
|
||||
public class UInt16Input : UserInput<ushort?>
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Text;
|
||||
namespace SabreTools.CommandLine.Inputs
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a user input bounded to the range of <see cref="uint"/>
|
||||
/// Represents a user input bounded to the range of <see cref="uint"/>
|
||||
/// </summary>
|
||||
public class UInt32Input : UserInput<uint?>
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Text;
|
||||
namespace SabreTools.CommandLine.Inputs
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a user input bounded to the range of <see cref="ulong"/>
|
||||
/// Represents a user input bounded to the range of <see cref="ulong"/>
|
||||
/// </summary>
|
||||
public class UInt64Input : UserInput<ulong?>
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Text;
|
||||
namespace SabreTools.CommandLine.Inputs
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a user input bounded to the range of <see cref="byte"/>
|
||||
/// Represents a user input bounded to the range of <see cref="byte"/>
|
||||
/// </summary>
|
||||
public class UInt8Input : UserInput<byte?>
|
||||
{
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace SabreTools.CommandLine.Inputs
|
||||
/// <summary>
|
||||
/// Set of children associated with this input
|
||||
/// </summary>
|
||||
protected readonly Dictionary<string, UserInput> Children = [];
|
||||
protected internal readonly Dictionary<string, UserInput> Children = [];
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace SabreTools.CommandLine.Inputs
|
||||
/// </summary>
|
||||
public UserInput? this[UserInput subfeature]
|
||||
{
|
||||
get
|
||||
get
|
||||
{
|
||||
if (!Children.TryGetValue(subfeature.Name, out var input))
|
||||
return null;
|
||||
@@ -135,6 +135,19 @@ namespace SabreTools.CommandLine.Inputs
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a Feature value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <returns>The value if found, null otherwise</returns>
|
||||
public Feature? GetFeature(string key)
|
||||
{
|
||||
if (TryGetFeature(key, out Feature? value))
|
||||
return value;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an Int8 value from a named input
|
||||
/// </summary>
|
||||
@@ -298,7 +311,7 @@ namespace SabreTools.CommandLine.Inputs
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new ArgumentException("Feature is not a bool");
|
||||
throw new ArgumentException("Input is not a bool");
|
||||
}
|
||||
|
||||
// Check all children recursively
|
||||
@@ -312,6 +325,35 @@ namespace SabreTools.CommandLine.Inputs
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a Feature value from a named input
|
||||
/// </summary>
|
||||
/// <param name="key">Input name to retrieve, if possible</param>
|
||||
/// <param name="value">Value that was found, default value otherwise</param>
|
||||
/// <returns>True if the value was found, false otherwise</returns>
|
||||
public bool TryGetFeature(string key, out Feature? value)
|
||||
{
|
||||
// Try to check immediate children
|
||||
if (Children.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not Feature i)
|
||||
throw new ArgumentException("Input is not a Feature");
|
||||
|
||||
value = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check all children recursively
|
||||
foreach (var child in Children.Values)
|
||||
{
|
||||
if (child.TryGetFeature(key, out value))
|
||||
return true;
|
||||
}
|
||||
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an Int8 value from a named input
|
||||
/// </summary>
|
||||
@@ -325,7 +367,7 @@ namespace SabreTools.CommandLine.Inputs
|
||||
if (Children.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not Int8Input i)
|
||||
throw new ArgumentException("Feature is not an sbyte");
|
||||
throw new ArgumentException("Input is not an sbyte");
|
||||
|
||||
value = i.Value ?? defaultValue;
|
||||
return true;
|
||||
@@ -355,7 +397,7 @@ namespace SabreTools.CommandLine.Inputs
|
||||
if (Children.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not Int16Input i)
|
||||
throw new ArgumentException("Feature is not a short");
|
||||
throw new ArgumentException("Input is not a short");
|
||||
|
||||
value = i.Value ?? defaultValue;
|
||||
return true;
|
||||
@@ -385,7 +427,7 @@ namespace SabreTools.CommandLine.Inputs
|
||||
if (Children.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not Int32Input i)
|
||||
throw new ArgumentException("Feature is not an int");
|
||||
throw new ArgumentException("Input is not an int");
|
||||
|
||||
value = i.Value ?? defaultValue;
|
||||
return true;
|
||||
@@ -415,7 +457,7 @@ namespace SabreTools.CommandLine.Inputs
|
||||
if (Children.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not Int64Input l)
|
||||
throw new ArgumentException("Feature is not a long");
|
||||
throw new ArgumentException("Input is not a long");
|
||||
|
||||
value = l.Value ?? defaultValue;
|
||||
return true;
|
||||
@@ -445,7 +487,7 @@ namespace SabreTools.CommandLine.Inputs
|
||||
if (Children.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not StringInput s)
|
||||
throw new ArgumentException("Feature is not a string");
|
||||
throw new ArgumentException("Input is not a string");
|
||||
|
||||
value = s.Value ?? defaultValue;
|
||||
return true;
|
||||
@@ -474,7 +516,7 @@ namespace SabreTools.CommandLine.Inputs
|
||||
if (Children.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not StringListInput l)
|
||||
throw new ArgumentException("Feature is not a list");
|
||||
throw new ArgumentException("Input is not a list");
|
||||
|
||||
value = l.Value ?? [];
|
||||
return true;
|
||||
@@ -504,7 +546,7 @@ namespace SabreTools.CommandLine.Inputs
|
||||
if (Children.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not UInt8Input i)
|
||||
throw new ArgumentException("Feature is not an byte");
|
||||
throw new ArgumentException("Input is not an byte");
|
||||
|
||||
value = i.Value ?? defaultValue;
|
||||
return true;
|
||||
@@ -534,7 +576,7 @@ namespace SabreTools.CommandLine.Inputs
|
||||
if (Children.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not UInt16Input i)
|
||||
throw new ArgumentException("Feature is not a ushort");
|
||||
throw new ArgumentException("Input is not a ushort");
|
||||
|
||||
value = i.Value ?? defaultValue;
|
||||
return true;
|
||||
@@ -564,7 +606,7 @@ namespace SabreTools.CommandLine.Inputs
|
||||
if (Children.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not UInt32Input i)
|
||||
throw new ArgumentException("Feature is not an uint");
|
||||
throw new ArgumentException("Input is not an uint");
|
||||
|
||||
value = i.Value ?? defaultValue;
|
||||
return true;
|
||||
@@ -594,7 +636,7 @@ namespace SabreTools.CommandLine.Inputs
|
||||
if (Children.TryGetValue(key, out var input))
|
||||
{
|
||||
if (input is not UInt64Input l)
|
||||
throw new ArgumentException("Feature is not a ulong");
|
||||
throw new ArgumentException("Input is not a ulong");
|
||||
|
||||
value = l.Value ?? defaultValue;
|
||||
return true;
|
||||
|
||||
@@ -27,10 +27,10 @@ namespace SabreTools.CommandLine.Inputs
|
||||
#region Instance Methods
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override abstract bool ProcessInput(string[] args, ref int index);
|
||||
public abstract override bool ProcessInput(string[] args, ref int index);
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override abstract string FormatFlags();
|
||||
protected abstract override string FormatFlags();
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Assembly Properties -->
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
@@ -11,7 +11,7 @@
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Version>1.3.1</Version>
|
||||
<Version>1.4.0</Version>
|
||||
|
||||
<!-- Package Properties -->
|
||||
<Authors>Matt Nadareski</Authors>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#! /bin/bash
|
||||
|
||||
# This batch file assumes the following:
|
||||
# - .NET 9.0 (or newer) SDK is installed and in PATH
|
||||
# - .NET 10.0 (or newer) SDK is installed and in PATH
|
||||
#
|
||||
# If any of these are not satisfied, the operation may fail
|
||||
# in an unpredictable way and result in an incomplete output.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# This batch file assumes the following:
|
||||
# - .NET 9.0 (or newer) SDK is installed and in PATH
|
||||
# - .NET 10.0 (or newer) SDK is installed and in PATH
|
||||
#
|
||||
# If any of these are not satisfied, the operation may fail
|
||||
# in an unpredictable way and result in an incomplete output.
|
||||
|
||||
Reference in New Issue
Block a user