Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
27 changes: 25 additions & 2 deletions src/chocolatey.resources/helpers/ChocolateyTabExpansion.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ $commandOptions = @{
pin = "--name='' --version=''"
push = "--api-key='' --source=''"
rule = "--name=''"
search = "--all-versions --approved-only --by-id-only --by-tag-only --cert='' --certpassword='' --detail --disable-repository-optimizations --download-cache-only --exact --id-only --id-starts-with --include-configured-sources --include-programs --not-broken --order-by-popularity --page='' --page-size='' --password='' --prerelease --source='' --user=''"
search = "--all-versions --approved-only --by-id-only --by-tag-only --cert='' --certpassword='' --detail --disable-repository-optimizations --download-cache-only --exact --id-only --id-starts-with --include-configured-sources --include-programs --not-broken --order-by='' --order-by-popularity --page='' --page-size='' --password='' --prerelease --source='' --user=''"
source = "--admin-only --allow-self-service --bypass-proxy --cert='' --certpassword='' --name='' --password='' --priority='' --source='' --user=''"
support = ""
template = "--name=''"
Expand Down Expand Up @@ -155,7 +155,7 @@ function script:chocoRemotePackages($filter) {
if ($filter -and $filter.StartsWith(".")) {
return;
} #file search
@('packages.config|') + @(& $script:choco search $filter --page='0' --page-size='30' -r --id-starts-with --order-by-popularity) |
@('packages.config|') + @(& $script:choco search $filter --page='0' --page-size='30' -r --id-starts-with --order-by='popularity') |
Where-Object { $_ -like "$filter*" } |
ForEach-Object { $_.Split('|')[0] }
}
Expand All @@ -166,6 +166,22 @@ function Get-AliasPattern($exe) {
"($($aliases -join '|'))"
}

function Get-ChocoOrderByOptions {
<#
.SYNOPSIS
Returns the list of canonical --order-by values for Chocolatey.

.DESCRIPTION
These values correspond to the distinct, non-aliased entries in the
PackageOrder enum. They are sorted alphabetically and must be updated
manually when the enum changes.

.OUTPUTS
A string in the format "Id|LastPublished|Popularity|Title|Unsorted"
#>
return @("Id", "LastPublished", "Popularity", "Title", "Unsorted")
}

function ChocolateyTabExpansion($lastBlock) {
switch -regex ($lastBlock -replace "^$(Get-AliasPattern choco) ", "") {

Expand Down Expand Up @@ -254,6 +270,13 @@ function ChocolateyTabExpansion($lastBlock) {
chocoLocalPackagesUpgrade $matches['package']
}

# Custom completion for --order-by values
"^search.*--order-by='?(?<prefix>.*)'?$" {
$prefix = $matches['prefix']
return Get-ChocoOrderByOptions | Where-Object { $_ -like "$prefix*" } | ForEach-Object { "--order-by='$_'"}
}


# Handles more options after others
"^(?<cmd>$($commandOptions.Keys -join '|'))(?<currentArguments>.*)\s+(?<op>\S*)$" {
chocoCmdOperations $commandOptions $matches['cmd'] $matches['op'] $matches['currentArguments']
Expand Down
29 changes: 29 additions & 0 deletions src/chocolatey.tests/MockLoggerExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright © 2017 - 2025 Chocolatey Software, Inc
// Copyright © 2011 - 2017 RealDimensions Software, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
//
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using FluentAssertions;

namespace chocolatey.tests
{
public static class MockLoggerExtensions
{
public static void ShouldHaveWarningContaining(this MockLogger logger, string expectedSubstring)
{
logger.Messages.Should().ContainKey(LogLevel.Warn.ToString())
.WhoseValue.Should().Contain(w => w.Contains(expectedSubstring));
}
}
}
2 changes: 2 additions & 0 deletions src/chocolatey.tests/chocolatey.tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@
<Compile Include="infrastructure.app\services\ChocolateyConfigSettingsServiceSpecs.cs" />
<Compile Include="infrastructure.app\services\ChocolateyPackageServiceSpecs.cs" />
<Compile Include="infrastructure.app\services\FilesServiceSpecs.cs" />
<Compile Include="infrastructure.app\services\NugetListSpecs.cs" />
<Compile Include="infrastructure.app\services\NugetServiceSpecs.cs" />
<Compile Include="infrastructure.app\services\RegistryServiceSpecs.cs" />
<Compile Include="infrastructure.app\services\RulesServiceSpecs.cs" />
Expand All @@ -205,6 +206,7 @@
<Compile Include="infrastructure\tolerance\FaultToleranceSpecs.cs" />
<Compile Include="infrastructure.app\utility\PackageUtilitySpecs.cs" />
<Compile Include="MockLogger.cs" />
<Compile Include="MockLoggerExtensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TinySpec.cs" />
<Compile Include="UNCHelper.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
using chocolatey.infrastructure.commandline;
using Moq;
using FluentAssertions;
using chocolatey.infrastructure.app.domain;

namespace chocolatey.tests.infrastructure.app.commands
{
Expand All @@ -38,6 +39,8 @@ public abstract class ChocolateySearchCommandSpecsBase : TinySpec

public override void Context()
{
MockLogger.Reset();

Configuration.Sources = "bob";
Command = new ChocolateySearchCommand(PackageService.Object);
}
Expand Down Expand Up @@ -259,6 +262,24 @@ public void Should_add_short_version_of_password_to_the_option_set()
{
_optionSet.Contains("p").Should().BeTrue();
}

[Fact]
public void Should_add_order_by_to_the_option_set()
{
_optionSet.Contains("order-by").Should().BeTrue();
}

[Fact]
public void Should_add_order_by_popularity_to_the_option_set()
{
_optionSet.Contains("order-by-popularity").Should().BeTrue();
}

[Fact]
public void Should_have_marked_order_by_popularity_as_deprecated()
{
_optionSet["order-by-popularity"].Description.Should().Contain("Deprecated");
}
}

public class When_handling_additional_argument_parsing : ChocolateySearchCommandSpecsBase
Expand Down Expand Up @@ -316,6 +337,192 @@ public void Should_call_service_list_noop()
}
}

[NUnit.Framework.TestFixtureSource(nameof(TestOrders))]
public class When_handling_order_by_parameter_correctly_parses_argument : ChocolateySearchCommandSpecsBase
{
private OptionSet _optionSet;
private OptionContext _optionContext;
private PackageOrder _order;
private string _orderString;

public When_handling_order_by_parameter_correctly_parses_argument(string orderString)
{
_orderString = orderString;
_order = (PackageOrder)Enum.Parse(typeof(PackageOrder), _orderString);
}

private static object[] TestOrders
{
get
{
var values = Enum.GetNames(typeof(PackageOrder));
var result = new List<object>();

foreach (var value in values)
{
result.Add(new object[] { value });
}

return result.ToArray();
}
}

public override void Context()
{
base.Context();

_optionSet = new OptionSet();
Command.ConfigureArgumentParser(_optionSet, Configuration);
_optionContext = new OptionContext(_optionSet)
{
Option = _optionSet["order-by"]
};
_optionContext.OptionName = _optionContext.Option.Names.First();
_optionContext.OptionValues.Add(_orderString);
}

public override void Because()
{
_optionContext.Option.Invoke(_optionContext);
}

[Fact]
public void Should_have_set_expected_package_sort_on_config()
{
Configuration.ListCommand.OrderBy.Should().Be(_order);
}
}

[NUnit.Framework.TestFixture(null)]
[NUnit.Framework.TestFixture("")]
public class When_handling_order_by_with_empty_values : ChocolateySearchCommandSpecsBase
{
private OptionSet _optionSet;
private OptionContext _optionContext;
private Exception _ex = null;
private string _testValue;

public When_handling_order_by_with_empty_values(string testValue)
{
_testValue = testValue;
}

public override void Context()
{
base.Context();

_optionSet = new OptionSet();
Command.ConfigureArgumentParser(_optionSet, Configuration);
_optionContext = new OptionContext(_optionSet)
{
Option = _optionSet["order-by"]
};
_optionContext.OptionName = _optionContext.Option.Names.First();
_optionContext.OptionValues.Add(_testValue);
}

public override void Because()
{
try
{
_optionContext.Option.Invoke(_optionContext);
}
catch (Exception ex)
{
_ex = ex;
}
}

[Fact]
public void Should_have_thrown_expected_exception()
{
_ex.Should().NotBeNull()
.And.BeOfType<ApplicationException>()
.Which.Message.Should().StartWith("No '--order-by' clause was provided. Specify one of the supported clauses:");
}
}

public class When_handling_order_by_with_unsupported_value : ChocolateySearchCommandSpecsBase
{
private OptionSet _optionSet;
private OptionContext _optionContext;
private Exception _ex = null;

public override void Context()
{
base.Context();

_optionSet = new OptionSet();
Command.ConfigureArgumentParser(_optionSet, Configuration);
_optionContext = new OptionContext(_optionSet)
{
Option = _optionSet["order-by"]
};
_optionContext.OptionName = _optionContext.Option.Names.First();
_optionContext.OptionValues.Add("NotExisting");
}

public override void Because()
{
try
{
_optionContext.Option.Invoke(_optionContext);
}
catch (Exception ex)
{
_ex = ex;
}
}

[Fact]
public void Should_have_thrown_expected_exception()
{
_ex.Should().NotBeNull()
.And.BeOfType<ApplicationException>()
.Which.Message.Should().StartWith("The '--order-by' clause 'NotExisting' is not recognized. Use one of the supported clauses:");
}
}

public class When_handling_order_by_popularity : ChocolateySearchCommandSpecsBase
{
private OptionSet _optionSet;
private OptionContext _optionContext;

public override void Context()
{
base.Context();

_optionSet = new OptionSet();
Command.ConfigureArgumentParser(_optionSet, Configuration);
_optionContext = new OptionContext(_optionSet)
{
Option = _optionSet["order-by-popularity"]
};
_optionContext.OptionName = _optionContext.Option.Names.First();
_optionContext.OptionValues.Add(bool.TrueString);
}

public override void Because()
{
_optionContext.Option.Invoke(_optionContext);
}

[Fact]
public void Should_have_set_expected_order_by_property_value()
{
Configuration.ListCommand.OrderBy.Should().Be(PackageOrder.Popularity);
}

[Fact]
public void Should_have_outputted_warning_message()
{
MockLogger.Messages.Should()
.ContainKey(LogLevel.Warn.ToString())
.WhoseValue.Should().Contain(@"'--order-by-popularity' is deprecated and will be removed in a future release.
Use '--order-by='Popularity'' instead.");
}
}

public class When_noop_is_called : ChocolateySearchCommandSpecsBase
{
public override void Because()
Expand Down
Loading