Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
<PackageVersion Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.6" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="System.Memory" Version="4.5.5" />
<PackageVersion Include="Verify.Xunit" Version="28.13.0" />
<PackageVersion Include="Verify.DiffPlex" Version="3.1.2" />
</ItemGroup>

<ItemGroup Condition="'$(DisableArcade)' == '1'">
Expand Down
30 changes: 30 additions & 0 deletions System.CommandLine.sln
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-suggest.Tests", "src
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.CommandLine.ApiCompatibility.Tests", "src\System.CommandLine.ApiCompatibility.Tests\System.CommandLine.ApiCompatibility.Tests.csproj", "{A54EE328-D456-4BAF-A180-84E77E6409AC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.CommandLine.StaticCompletions", "src\System.CommandLine.StaticCompletions\System.CommandLine.StaticCompletions.csproj", "{B1C3A2F4-5D6E-7F8A-9B0C-1D2E3F4A5B6C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.CommandLine.StaticCompletions.Tests", "src\System.CommandLine.StaticCompletions.Tests\System.CommandLine.StaticCompletions.Tests.csproj", "{C2D3E4F5-6A7B-8C9D-0E1F-2A3B4C5D6E7F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -101,6 +105,30 @@ Global
{A54EE328-D456-4BAF-A180-84E77E6409AC}.Release|x64.Build.0 = Release|Any CPU
{A54EE328-D456-4BAF-A180-84E77E6409AC}.Release|x86.ActiveCfg = Release|Any CPU
{A54EE328-D456-4BAF-A180-84E77E6409AC}.Release|x86.Build.0 = Release|Any CPU
{B1C3A2F4-5D6E-7F8A-9B0C-1D2E3F4A5B6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B1C3A2F4-5D6E-7F8A-9B0C-1D2E3F4A5B6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B1C3A2F4-5D6E-7F8A-9B0C-1D2E3F4A5B6C}.Debug|x64.ActiveCfg = Debug|Any CPU
{B1C3A2F4-5D6E-7F8A-9B0C-1D2E3F4A5B6C}.Debug|x64.Build.0 = Debug|Any CPU
{B1C3A2F4-5D6E-7F8A-9B0C-1D2E3F4A5B6C}.Debug|x86.ActiveCfg = Debug|Any CPU
{B1C3A2F4-5D6E-7F8A-9B0C-1D2E3F4A5B6C}.Debug|x86.Build.0 = Debug|Any CPU
{B1C3A2F4-5D6E-7F8A-9B0C-1D2E3F4A5B6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B1C3A2F4-5D6E-7F8A-9B0C-1D2E3F4A5B6C}.Release|Any CPU.Build.0 = Release|Any CPU
{B1C3A2F4-5D6E-7F8A-9B0C-1D2E3F4A5B6C}.Release|x64.ActiveCfg = Release|Any CPU
{B1C3A2F4-5D6E-7F8A-9B0C-1D2E3F4A5B6C}.Release|x64.Build.0 = Release|Any CPU
{B1C3A2F4-5D6E-7F8A-9B0C-1D2E3F4A5B6C}.Release|x86.ActiveCfg = Release|Any CPU
{B1C3A2F4-5D6E-7F8A-9B0C-1D2E3F4A5B6C}.Release|x86.Build.0 = Release|Any CPU
{C2D3E4F5-6A7B-8C9D-0E1F-2A3B4C5D6E7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C2D3E4F5-6A7B-8C9D-0E1F-2A3B4C5D6E7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C2D3E4F5-6A7B-8C9D-0E1F-2A3B4C5D6E7F}.Debug|x64.ActiveCfg = Debug|Any CPU
{C2D3E4F5-6A7B-8C9D-0E1F-2A3B4C5D6E7F}.Debug|x64.Build.0 = Debug|Any CPU
{C2D3E4F5-6A7B-8C9D-0E1F-2A3B4C5D6E7F}.Debug|x86.ActiveCfg = Debug|Any CPU
{C2D3E4F5-6A7B-8C9D-0E1F-2A3B4C5D6E7F}.Debug|x86.Build.0 = Debug|Any CPU
{C2D3E4F5-6A7B-8C9D-0E1F-2A3B4C5D6E7F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C2D3E4F5-6A7B-8C9D-0E1F-2A3B4C5D6E7F}.Release|Any CPU.Build.0 = Release|Any CPU
{C2D3E4F5-6A7B-8C9D-0E1F-2A3B4C5D6E7F}.Release|x64.ActiveCfg = Release|Any CPU
{C2D3E4F5-6A7B-8C9D-0E1F-2A3B4C5D6E7F}.Release|x64.Build.0 = Release|Any CPU
{C2D3E4F5-6A7B-8C9D-0E1F-2A3B4C5D6E7F}.Release|x86.ActiveCfg = Release|Any CPU
{C2D3E4F5-6A7B-8C9D-0E1F-2A3B4C5D6E7F}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -111,6 +139,8 @@ Global
{E23C760E-B826-4B4F-BE76-916D86BAD2DB} = {E5B1EC71-0FC4-4FAA-9C65-32D5016FBC45}
{E41F0471-B14D-4FA0-9D8B-1E7750695AE9} = {E5B1EC71-0FC4-4FAA-9C65-32D5016FBC45}
{A54EE328-D456-4BAF-A180-84E77E6409AC} = {E5B1EC71-0FC4-4FAA-9C65-32D5016FBC45}
{B1C3A2F4-5D6E-7F8A-9B0C-1D2E3F4A5B6C} = {E5B1EC71-0FC4-4FAA-9C65-32D5016FBC45}
{C2D3E4F5-6A7B-8C9D-0E1F-2A3B4C5D6E7F} = {E5B1EC71-0FC4-4FAA-9C65-32D5016FBC45}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5C159F93-800B-49E7-9905-EE09F8B8434A}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

namespace System.CommandLine.StaticCompletions.Tests;

using System.CommandLine.StaticCompletions.Shells;

public class BashShellProviderTests(ITestOutputHelper log)
{
private IShellProvider provider = new BashShellProvider();
[Fact]
public async Task GenericCompletions()
{
await provider.Verify(new("mycommand"), log);
}

[Fact]
public async Task SimpleOptionCompletion()
{
await provider.Verify(new("mycommand") {
new Option<string>("--name")
}, log);
}

[Fact]
public async Task SubcommandAndOptionInTopLevelList()
{
await provider.Verify(new("mycommand") {
new Option<string>("--name"),
new Command("subcommand")
}, log);
}

[Fact]
public async Task NestedSubcommandCompletion()
{
await provider.Verify(new("mycommand") {
new Command("subcommand") {
new Command("nested")
}
}, log);
}

[Fact]
public async Task DynamicCompletionsGeneration()
{
var dynamicOption = new Option<string>("--name") { IsDynamic = true };
var dynamicArg = new Argument<string>("target") { IsDynamic = true };
await provider.Verify(new("mycommand") { dynamicOption, dynamicArg }, log);
}

[Fact]
public async Task DynamicCompletionsViaSubcommand()
{
var subcommandProvider = new BashShellProvider { Invocation = CompletionInvocation.Subcommand() };
var dynamicOption = new Option<string>("--name") { IsDynamic = true };
var dynamicArg = new Argument<string>("target") { IsDynamic = true };
await subcommandProvider.Verify(new("mycommand") { dynamicOption, dynamicArg }, log);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project>

<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.targets', '$(MSBuildThisFileDirectory)../'))" />

<!-- Microsoft.NET.Test.Sdk unconditionally sets OutputType=Exe, but this project uses
Arcade's xunit console runner (which invokes the DLL directly), so Library is correct. -->
<PropertyGroup>
<OutputType>Library</OutputType>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

global using Xunit;
global using Xunit.Abstractions;
global using FluentAssertions;
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

namespace System.CommandLine.StaticCompletions.Tests;

using System.CommandLine.Help;
using System.CommandLine.StaticCompletions;

public class HelpExtensionsTests
{
[Fact]
public void HelpOptionOnlyShowsUsefulNames()
{
new HelpOption().Names().Should().BeEquivalentTo(["--help", "-h"]);
}

[Fact]
public void OptionNamesListNameThenAliases()
{
new Option<string>("--name", "-n", "--nombre").Names().Should().Equal(["--name", "-n", "--nombre"]);
}

[Fact]
public void OptionsWithNoAliasesHaveOnlyOneName()
{
new Option<string>("--name").Names().Should().Equal(["--name"]);
}

[Fact]
public void HeirarchicalOptionsAreFlattened()
{
var parentCommand = new Command("parent");
var childCommand = new Command("child");
parentCommand.Subcommands.Add(childCommand);
parentCommand.Options.Add(new Option<string>("--parent-global") { Recursive = true });
parentCommand.Options.Add(new Option<string>("--parent-local") { Recursive = false });
parentCommand.Options.Add(new Option<string>("--parent-global-but-hidden") { Recursive = true, Hidden = true });

childCommand.Options.Add(new Option<string>("--child-local"));
childCommand.Options.Add(new Option<string>("--child-hidden") { Hidden = true });

// note: no parent-local or parent-global-but-hidden options, and no locally hidden options
childCommand.HierarchicalOptions().Select(c => c.Name).Should().Equal(["--child-local", "--parent-global"]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

namespace System.CommandLine.StaticCompletions.Tests;

using System.CommandLine.StaticCompletions.Shells;
using EmptyFiles;

public class PowershellProviderTests(ITestOutputHelper log)
{
private IShellProvider provider = new PowerShellShellProvider();

[Fact]
public async Task GenericCompletions()
{
await provider.Verify(new("mycommand"), log);
}

[Fact]
public async Task SimpleOptionCompletion()
{
await provider.Verify(new("mycommand") {
new Option<string>("--name")
}, log);
}

[Fact]
public async Task SubcommandAndOptionInTopLevelList()
{
await provider.Verify(new("mycommand") {
new Option<string>("--name"),
new Command("subcommand")
}, log);
}

[Fact]
public async Task NestedSubcommandCompletion()
{
await provider.Verify(new("mycommand") {
new Command("subcommand") {
new Command("nested")
}
}, log);
}

[Fact]
public async Task DynamicCompletionsGeneration()
{
var dynamicArg = new Argument<string>("target") { IsDynamic = true };
await provider.Verify(new("mycommand") { dynamicArg }, log);
}

[Fact]
public async Task DynamicCompletionsViaSubcommand()
{
var subcommandProvider = new PowerShellShellProvider { Invocation = CompletionInvocation.Subcommand() };
var dynamicArg = new Argument<string>("target") { IsDynamic = true };
await subcommandProvider.Verify(new("mycommand") { dynamicArg }, log);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(NetMinimum)</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateProgramFile>false</GenerateProgramFile>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\System.CommandLine.StaticCompletions\System.CommandLine.StaticCompletions.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Verify.Xunit" />
<PackageReference Include="Verify.DiffPlex" />
<PackageReference Include="AwesomeAssertions" />
</ItemGroup>

<ItemGroup>
<Compile Remove="snapshots/**/*" />
<Content Include="snapshots/**/*" CopyToOutputDirectory="PreserveNewest" Pack="false" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

namespace System.CommandLine.StaticCompletions.Tests;

using System.Runtime.CompilerServices;

public static class VerifyConfiguration
{
[ModuleInitializer]
public static void Initialize()
{
VerifyDiffPlex.Initialize(VerifyTests.DiffPlex.OutputType.Compact);

if (Environment.GetEnvironmentVariable("CI") is string ci && ci.Equals("true", StringComparison.OrdinalIgnoreCase))
{
Verifier.DerivePathInfo((sourceFile, projectDirectory, type, method) => new(
directory: Path.Combine(Environment.CurrentDirectory, "snapshots"),
typeName: type.Name,
methodName: method.Name)
);
}

EmptyFiles.FileExtensions.AddTextExtension("ps1");
EmptyFiles.FileExtensions.AddTextExtension("nu");
}
}
18 changes: 18 additions & 0 deletions src/System.CommandLine.StaticCompletions.Tests/VerifyExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.CommandLine.StaticCompletions.Shells;
using System.Runtime.CompilerServices;

namespace System.CommandLine.StaticCompletions.Tests;

public static class VerifyExtensions
{
public static async Task Verify(this IShellProvider provider, Command command, ITestOutputHelper log, [CallerFilePath] string sourceFile = "")
{
var settings = new VerifySettings();
settings.UseDirectory(Path.Combine("snapshots", provider.ArgumentName));
var completions = provider.GenerateCompletions(command);
await Verifier.Verify(target: completions, extension: provider.Extension, settings: settings, sourceFile: sourceFile);
}
}
Loading