diff --git a/localization/strings/en-US/Resources.resw b/localization/strings/en-US/Resources.resw index ff843e40e..3e9587df5 100644 --- a/localization/strings/en-US/Resources.resw +++ b/localization/strings/en-US/Resources.resw @@ -2294,6 +2294,12 @@ On first run, creates the file with all settings commented out at their defaults Settings reset to defaults. + + Show version information. + + + Show version information for this tool. + Show all regardless of state. diff --git a/src/windows/wslc/commands/RootCommand.cpp b/src/windows/wslc/commands/RootCommand.cpp index 6c63c7e15..732c19404 100644 --- a/src/windows/wslc/commands/RootCommand.cpp +++ b/src/windows/wslc/commands/RootCommand.cpp @@ -18,6 +18,7 @@ Module Name: #include "ImageCommand.h" #include "SessionCommand.h" #include "SettingsCommand.h" +#include "VersionCommand.h" using namespace wsl::windows::wslc::execution; using namespace wsl::shared; @@ -47,6 +48,7 @@ std::vector> RootCommand::GetCommands() const commands.push_back(std::make_unique(FullName())); commands.push_back(std::make_unique(FullName())); commands.push_back(std::make_unique(FullName())); + commands.push_back(std::make_unique(FullName())); return commands; } @@ -71,7 +73,7 @@ void RootCommand::ExecuteInternal(CLIExecutionContext& context) const { if (context.Args.Contains(ArgType::Version)) { - wsl::windows::common::wslutil::PrintMessage(std::format(L"{} v{}", s_ExecutableName, WSL_PACKAGE_VERSION)); + VersionCommand::PrintVersion(); return; } diff --git a/src/windows/wslc/commands/VersionCommand.cpp b/src/windows/wslc/commands/VersionCommand.cpp new file mode 100644 index 000000000..eba4c565f --- /dev/null +++ b/src/windows/wslc/commands/VersionCommand.cpp @@ -0,0 +1,39 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + VersionCommand.cpp + +Abstract: + + Implementation of the version command. + +--*/ +#include "VersionCommand.h" + +using namespace wsl::windows::wslc::execution; + +namespace wsl::windows::wslc { +std::wstring VersionCommand::ShortDescription() const +{ + return Localization::WSLCCLI_VersionDesc(); +} + +std::wstring VersionCommand::LongDescription() const +{ + return Localization::WSLCCLI_VersionLongDesc(); +} + +void VersionCommand::PrintVersion() +{ + wsl::windows::common::wslutil::PrintMessage(std::format(L"{} {}", s_ExecutableName, WSL_PACKAGE_VERSION)); +} + +void VersionCommand::ExecuteInternal(CLIExecutionContext& context) const +{ + UNREFERENCED_PARAMETER(context); + PrintVersion(); +} +} // namespace wsl::windows::wslc diff --git a/src/windows/wslc/commands/VersionCommand.h b/src/windows/wslc/commands/VersionCommand.h new file mode 100644 index 000000000..be700f550 --- /dev/null +++ b/src/windows/wslc/commands/VersionCommand.h @@ -0,0 +1,31 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + VersionCommand.h + +Abstract: + + Declaration of the VersionCommand. + +--*/ +#pragma once +#include "Command.h" + +namespace wsl::windows::wslc { +struct VersionCommand final : public Command +{ + constexpr static std::wstring_view CommandName = L"version"; + VersionCommand(const std::wstring& parent) : Command(CommandName, parent) + { + } + static void PrintVersion(); + std::wstring ShortDescription() const override; + std::wstring LongDescription() const override; + +protected: + void ExecuteInternal(CLIExecutionContext& context) const override; +}; +} // namespace wsl::windows::wslc diff --git a/test/windows/wslc/CommandLineTestCases.h b/test/windows/wslc/CommandLineTestCases.h index ed1025fba..7a7b7008f 100644 --- a/test/windows/wslc/CommandLineTestCases.h +++ b/test/windows/wslc/CommandLineTestCases.h @@ -115,6 +115,10 @@ COMMAND_LINE_TEST_CASE(L"image list -q", L"list", true) COMMAND_LINE_TEST_CASE(L"image pull ubuntu", L"pull", true) COMMAND_LINE_TEST_CASE(L"pull ubuntu", L"pull", true) +// Version command tests +COMMAND_LINE_TEST_CASE(L"version", L"version", true) +COMMAND_LINE_TEST_CASE(L"version --help", L"version", true) +COMMAND_LINE_TEST_CASE(L"version extraarg", L"version", false) // Settings command COMMAND_LINE_TEST_CASE(L"settings", L"settings", true) COMMAND_LINE_TEST_CASE(L"settings reset", L"reset", true) diff --git a/test/windows/wslc/WSLCCLICommandUnitTests.cpp b/test/windows/wslc/WSLCCLICommandUnitTests.cpp index f72c63df3..e707c909c 100644 --- a/test/windows/wslc/WSLCCLICommandUnitTests.cpp +++ b/test/windows/wslc/WSLCCLICommandUnitTests.cpp @@ -20,6 +20,7 @@ Module Name: #include "RootCommand.h" #include "ContainerCommand.h" #include "SessionCommand.h" +#include "VersionCommand.h" using namespace wsl::windows::wslc; using namespace WSLCTestHelpers; @@ -95,6 +96,48 @@ class WSLCCLICommandUnitTests VERIFY_IS_NOT_NULL(subcmd.get()); } } + + // Test: Verify VersionCommand has the correct name + TEST_METHOD(VersionCommand_HasCorrectName) + { + auto cmd = VersionCommand(L"wslc"); + VERIFY_ARE_EQUAL(std::wstring_view(L"version"), cmd.Name()); + } + + // Test: Verify VersionCommand has no subcommands + TEST_METHOD(VersionCommand_HasNoSubcommands) + { + auto cmd = VersionCommand(L"wslc"); + VERIFY_ARE_EQUAL(0u, cmd.GetCommands().size()); + } + + // Test: Verify VersionCommand has no arguments (only the auto-added --help) + TEST_METHOD(VersionCommand_HasNoArguments) + { + auto cmd = VersionCommand(L"wslc"); + VERIFY_ARE_EQUAL(0u, cmd.GetArguments().size()); + // Test out that auto added help command is the only one + VERIFY_ARE_EQUAL(1u, cmd.GetAllArguments().size()); + } + + // Test: Verify RootCommand contains VersionCommand as a subcommand + TEST_METHOD(RootCommand_ContainsVersionCommand) + { + auto root = RootCommand(); + auto subcommands = root.GetCommands(); + + bool found = false; + for (const auto& subcmd : subcommands) + { + if (subcmd->Name() == VersionCommand::CommandName) + { + found = true; + break; + } + } + + VERIFY_IS_TRUE(found, L"RootCommand should contain VersionCommand"); + } }; } // namespace WSLCCLICommandUnitTests \ No newline at end of file diff --git a/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp b/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp index c4486ffc7..ae5fc2c57 100644 --- a/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp +++ b/test/windows/wslc/e2e/WSLCE2EGlobalTests.cpp @@ -51,6 +51,11 @@ class WSLCE2EGlobalTests RunWslcAndVerify(L"INVALID_CMD", {.Stdout = GetHelpMessage(), .Stderr = L"Unrecognized command: 'INVALID_CMD'\r\n", .ExitCode = 1}); } + TEST_METHOD(WSLCE2E_VersionCommand) + { + WSL2_TEST_ONLY(); + RunWslcAndVerify(L"version", {.Stdout = GetVersionMessage(), .Stderr = L"", .ExitCode = 0}); + } TEST_METHOD(WSLCE2E_Session_DefaultElevated) { WSL2_TEST_ONLY(); @@ -400,6 +405,11 @@ class WSLCE2EGlobalTests return output.str(); } + std::wstring GetVersionMessage() const + { + return std::format(L"wslc {}\r\n", WSL_PACKAGE_VERSION); + } + std::wstring GetDescription() const { return L"WSLC is the Windows Subsystem for Linux Container CLI tool. It enables management and interaction with WSL " @@ -435,6 +445,7 @@ class WSLCE2EGlobalTests {L"save", Localization::WSLCCLI_ImageSaveDesc()}, {L"start", Localization::WSLCCLI_ContainerStartDesc()}, {L"stop", Localization::WSLCCLI_ContainerStopDesc()}, + {L"version", Localization::WSLCCLI_VersionDesc()}, }; size_t maxLen = 0;