mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-07-02 10:58:17 +08:00
Move Spectre.Console.Cli to it's own package
This commit is contained in:

committed by
Patrik Svensson

parent
b600832e00
commit
36ca22ffac
316
test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Pairs.cs
Normal file
316
test/Spectre.Console.Cli.Tests/Unit/CommandAppTests.Pairs.cs
Normal file
@ -0,0 +1,316 @@
|
||||
namespace Spectre.Console.Tests.Unit.Cli;
|
||||
|
||||
public sealed partial class CommandAppTests
|
||||
{
|
||||
public sealed class Pairs
|
||||
{
|
||||
public sealed class AmbiguousSettings : CommandSettings
|
||||
{
|
||||
[CommandOption("--var <VALUE>")]
|
||||
[PairDeconstructor(typeof(StringIntDeconstructor))]
|
||||
[TypeConverter(typeof(CatAgilityConverter))]
|
||||
public ILookup<string, string> Values { get; set; }
|
||||
}
|
||||
|
||||
public sealed class NotDeconstructableSettings : CommandSettings
|
||||
{
|
||||
[CommandOption("--var <VALUE>")]
|
||||
[PairDeconstructor(typeof(StringIntDeconstructor))]
|
||||
public string Values { get; set; }
|
||||
}
|
||||
|
||||
public sealed class DefaultPairDeconstructorSettings : CommandSettings
|
||||
{
|
||||
[CommandOption("--var <VALUE>")]
|
||||
public IDictionary<string, int> Values { get; set; }
|
||||
}
|
||||
|
||||
public sealed class DefaultPairDeconstructorEnumValueSettings : CommandSettings
|
||||
{
|
||||
[CommandOption("--var <VALUE>")]
|
||||
public IDictionary<string, DayOfWeek> Values { get; set; }
|
||||
}
|
||||
|
||||
public sealed class LookupSettings : CommandSettings
|
||||
{
|
||||
[CommandOption("--var <VALUE>")]
|
||||
[PairDeconstructor(typeof(StringIntDeconstructor))]
|
||||
public ILookup<string, string> Values { get; set; }
|
||||
}
|
||||
|
||||
public sealed class DictionarySettings : CommandSettings
|
||||
{
|
||||
[CommandOption("--var <VALUE>")]
|
||||
[PairDeconstructor(typeof(StringIntDeconstructor))]
|
||||
public IDictionary<string, string> Values { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ReadOnlyDictionarySettings : CommandSettings
|
||||
{
|
||||
[CommandOption("--var <VALUE>")]
|
||||
[PairDeconstructor(typeof(StringIntDeconstructor))]
|
||||
public IReadOnlyDictionary<string, string> Values { get; set; }
|
||||
}
|
||||
|
||||
public sealed class StringIntDeconstructor : PairDeconstructor<string, string>
|
||||
{
|
||||
protected override (string Key, string Value) Deconstruct(string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
var parts = value.Split(new[] { '=' });
|
||||
if (parts.Length != 2)
|
||||
{
|
||||
throw new InvalidOperationException("Could not parse pair");
|
||||
}
|
||||
|
||||
return (parts[0], parts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Option_Has_Pair_Deconstructor_And_Type_Converter()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandApp<GenericCommand<AmbiguousSettings>>();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => app.Run(new[]
|
||||
{
|
||||
"--var", "foo=bar",
|
||||
"--var", "foo=qux",
|
||||
}));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
|
||||
{
|
||||
ex.Message.ShouldBe("The option 'var' is both marked as pair deconstructable and convertable.");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Throw_If_Option_Has_Pair_Deconstructor_But_Type_Is_Not_Deconstructable()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandApp<GenericCommand<NotDeconstructableSettings>>();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = Record.Exception(() => app.Run(new[]
|
||||
{
|
||||
"--var", "foo=bar",
|
||||
"--var", "foo=qux",
|
||||
}));
|
||||
|
||||
// Then
|
||||
result.ShouldBeOfType<CommandConfigurationException>().And(ex =>
|
||||
{
|
||||
ex.Message.ShouldBe("The option 'var' is marked as pair deconstructable, but the underlying type does not support that.");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Map_Pairs_To_Pair_Deconstructable_Collection_Using_Default_Deconstructort()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorSettings>>();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[]
|
||||
{
|
||||
"--var", "foo=1",
|
||||
"--var", "foo=3",
|
||||
"--var", "bar=4",
|
||||
});
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Settings.ShouldBeOfType<DefaultPairDeconstructorSettings>().And(pair =>
|
||||
{
|
||||
pair.Values.ShouldNotBeNull();
|
||||
pair.Values.Count.ShouldBe(2);
|
||||
pair.Values["foo"].ShouldBe(3);
|
||||
pair.Values["bar"].ShouldBe(4);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Map_Pairs_With_Enum_Value_To_Pair_Deconstructable_Collection_Using_Default_Deconstructor()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorEnumValueSettings>>();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[]
|
||||
{
|
||||
"--var", "foo=Monday",
|
||||
"--var", "bar=Tuesday",
|
||||
});
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Settings.ShouldBeOfType<DefaultPairDeconstructorEnumValueSettings>().And(pair =>
|
||||
{
|
||||
pair.Values.ShouldNotBeNull();
|
||||
pair.Values.Count.ShouldBe(2);
|
||||
pair.Values["foo"].ShouldBe(DayOfWeek.Monday);
|
||||
pair.Values["bar"].ShouldBe(DayOfWeek.Tuesday);
|
||||
});
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("foo=1=2", "Error: The value 'foo=1=2' is not in a correct format")]
|
||||
[InlineData("foo=1=2=3", "Error: The value 'foo=1=2=3' is not in a correct format")]
|
||||
public void Should_Throw_If_Value_Is_Not_In_A_Valid_Format_Using_Default_Deconstructor(
|
||||
string input, string expected)
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.SetDefaultCommand<GenericCommand<DefaultPairDeconstructorSettings>>();
|
||||
|
||||
// When
|
||||
var result = app.Run(new[]
|
||||
{
|
||||
"--var", input,
|
||||
});
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(-1);
|
||||
result.Output.ShouldBe(expected);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Map_Lookup_Values()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.SetDefaultCommand<GenericCommand<LookupSettings>>();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[]
|
||||
{
|
||||
"--var", "foo=bar",
|
||||
"--var", "foo=qux",
|
||||
});
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Settings.ShouldBeOfType<LookupSettings>().And(pair =>
|
||||
{
|
||||
pair.Values.ShouldNotBeNull();
|
||||
pair.Values.Count.ShouldBe(1);
|
||||
pair.Values["foo"].ToList().Count.ShouldBe(2);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Map_Dictionary_Values()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.SetDefaultCommand<GenericCommand<DictionarySettings>>();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[]
|
||||
{
|
||||
"--var", "foo=bar",
|
||||
"--var", "baz=qux",
|
||||
});
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Settings.ShouldBeOfType<DictionarySettings>().And(pair =>
|
||||
{
|
||||
pair.Values.ShouldNotBeNull();
|
||||
pair.Values.Count.ShouldBe(2);
|
||||
pair.Values["foo"].ShouldBe("bar");
|
||||
pair.Values["baz"].ShouldBe("qux");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Map_Latest_Value_Of_Same_Key_When_Mapping_To_Dictionary()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.SetDefaultCommand<GenericCommand<DictionarySettings>>();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[]
|
||||
{
|
||||
"--var", "foo=bar",
|
||||
"--var", "foo=qux",
|
||||
});
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Settings.ShouldBeOfType<DictionarySettings>().And(pair =>
|
||||
{
|
||||
pair.Values.ShouldNotBeNull();
|
||||
pair.Values.Count.ShouldBe(1);
|
||||
pair.Values["foo"].ShouldBe("qux");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_Map_ReadOnly_Dictionary_Values()
|
||||
{
|
||||
// Given
|
||||
var app = new CommandAppTester();
|
||||
app.SetDefaultCommand<GenericCommand<ReadOnlyDictionarySettings>>();
|
||||
app.Configure(config =>
|
||||
{
|
||||
config.PropagateExceptions();
|
||||
});
|
||||
|
||||
// When
|
||||
var result = app.Run(new[]
|
||||
{
|
||||
"--var", "foo=bar",
|
||||
"--var", "baz=qux",
|
||||
});
|
||||
|
||||
// Then
|
||||
result.ExitCode.ShouldBe(0);
|
||||
result.Settings.ShouldBeOfType<ReadOnlyDictionarySettings>().And(pair =>
|
||||
{
|
||||
pair.Values.ShouldNotBeNull();
|
||||
pair.Values.Count.ShouldBe(2);
|
||||
pair.Values["foo"].ShouldBe("bar");
|
||||
pair.Values["baz"].ShouldBe("qux");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user