winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

Completion.cpp (20272B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "TestCommon.h"
      5 #include <AppInstallerErrors.h>
      6 #include <Command.h>
      7 #include <Commands/CompleteCommand.h>
      8 #include <Commands/RootCommand.h>
      9 #include <Commands/SourceCommand.h>
     10 #include <CompletionData.h>
     11 
     12 using namespace std::string_literals;
     13 using namespace std::string_view_literals;
     14 using namespace TestCommon;
     15 using namespace AppInstaller;
     16 using namespace AppInstaller::CLI;
     17 using namespace AppInstaller::CLI::Execution;
     18 
     19 
     20 TEST_CASE("CompletionData_EmptyWord_PositionAtEnd", "[complete]")
     21 {
     22     CompletionData cd{ "", "winget ", "7" };
     23     REQUIRE(cd.Word() == "");
     24     REQUIRE(cd.BeforeWord().size() == 0);
     25     REQUIRE(cd.AfterWord().size() == 0);
     26 }
     27 
     28 TEST_CASE("CompletionData_EmptyWord_PositionPastEnd", "[complete]")
     29 {
     30     CompletionData cd{ "", "winget ", "8" };
     31     REQUIRE(cd.Word() == "");
     32     REQUIRE(cd.BeforeWord().size() == 0);
     33     REQUIRE(cd.AfterWord().size() == 0);
     34 }
     35 
     36 TEST_CASE("CompletionData_EmptyWord_PositionCorrect", "[complete]")
     37 {
     38     CompletionData cd{ "", "winget install", "7" };
     39     REQUIRE(cd.Word() == "");
     40     REQUIRE(cd.BeforeWord().size() == 0);
     41     REQUIRE(cd.AfterWord().size() == 1);
     42 }
     43 
     44 
     45 TEST_CASE("CompletionData_EmptyWord_PositionOffset", "[complete]")
     46 {
     47     CompletionData cd{ "", "winget install PowerToys --version", "17" };
     48     REQUIRE(cd.Word() == "");
     49     REQUIRE(cd.BeforeWord().size() == 1);
     50     REQUIRE(cd.AfterWord().size() == 2);
     51 }
     52 
     53 TEST_CASE("CompletionData_Word_NoMatch", "[complete]")
     54 {
     55     auto lambda = []() { CompletionData cd{ "foo", "winget install PowerToys --version", "17" }; };
     56     REQUIRE_THROWS_HR(lambda(), APPINSTALLER_CLI_ERROR_COMPLETE_INPUT_BAD);
     57 }
     58 
     59 TEST_CASE("CompletionData_Word_SingleMatch", "[complete]")
     60 {
     61     CompletionData cd{ "power", "winget install power --version", "17" };
     62     REQUIRE(cd.Word() == "power");
     63     REQUIRE(cd.BeforeWord().size() == 1);
     64     REQUIRE(cd.AfterWord().size() == 1);
     65 }
     66 
     67 TEST_CASE("CompletionData_Word_MultiMatch_PositionCorrect", "[complete]")
     68 {
     69     CompletionData cd{ "power", "winget install power --id power", "27" };
     70     REQUIRE(cd.Word() == "power");
     71     REQUIRE(cd.BeforeWord().size() == 3);
     72     REQUIRE(cd.AfterWord().size() == 0);
     73 }
     74 
     75 TEST_CASE("CompletionData_Word_MultiMatch_PositionOffset", "[complete]")
     76 {
     77     CompletionData cd{ "power", "winget install power --id power", "21" };
     78     REQUIRE(cd.Word() == "power");
     79     REQUIRE(cd.BeforeWord().size() == 1);
     80     REQUIRE(cd.AfterWord().size() == 2);
     81 }
     82 
     83 TEST_CASE("CompletionData_UTF8_EmptyWord_End", "[complete]")
     84 {
     85     CompletionData cd{ "", u8"winget install \x175\x12b\x14b\x1e5\x229\x288 --version ", "32" };
     86     REQUIRE(cd.Word() == "");
     87     REQUIRE(cd.BeforeWord().size() == 3);
     88     REQUIRE(cd.AfterWord().size() == 0);
     89 }
     90 
     91 TEST_CASE("CompletionData_UTF8_EmptyWord_Middle", "[complete]")
     92 {
     93     CompletionData cd{ "", u8"winget install \x175\x12b\x14b\x1e5\x229\x288 --version ", "22" };
     94     REQUIRE(cd.Word() == "");
     95     REQUIRE(cd.BeforeWord().size() == 2);
     96     REQUIRE(cd.AfterWord().size() == 1);
     97 }
     98 
     99 TEST_CASE("CompletionData_UTF8_UTF8Word", "[complete]")
    100 {
    101     CompletionData cd{ u8"\x175\x12b\x14b\x1e5\x229\x288", u8"winget install \x175\x12b\x14b\x1e5\x229\x288 --version ", "18" };
    102     REQUIRE(cd.Word() == u8"\x175\x12b\x14b\x1e5\x229\x288");
    103     REQUIRE(cd.BeforeWord().size() == 1);
    104     REQUIRE(cd.AfterWord().size() == 1);
    105 }
    106 
    107 void OutputAllSubCommands(Command& command, std::ostream& out, std::string_view filter = {})
    108 {
    109     for (const auto& c : command.GetCommands())
    110     {
    111         if (Utility::CaseInsensitiveStartsWith(c->Name(), filter))
    112         {
    113             out << c->Name() << std::endl;
    114         }
    115     }
    116 }
    117 
    118 void OutputAllArgumentNames(Command& command, std::ostream& out, std::string_view filter = {}, bool includeCommon = true)
    119 {
    120     auto args = command.GetArguments();
    121     if (includeCommon)
    122     {
    123         Argument::GetCommon(args);
    124     }
    125 
    126     for (const auto& a : args)
    127     {
    128         if (Utility::CaseInsensitiveStartsWith(a.Name(), filter))
    129         {
    130             out << APPINSTALLER_CLI_ARGUMENT_IDENTIFIER_CHAR << APPINSTALLER_CLI_ARGUMENT_IDENTIFIER_CHAR << a.Name() << std::endl;
    131         }
    132     }
    133 }
    134 
    135 void OutputAllArgumentAliases(Command& command, std::ostream& out, bool includeCommon = true)
    136 {
    137     auto args = command.GetArguments();
    138     if (includeCommon)
    139     {
    140         Argument::GetCommon(args);
    141     }
    142 
    143     for (const auto& a : args)
    144     {
    145         if (a.Alias() != ArgumentCommon::NoAlias)
    146         {
    147             out << APPINSTALLER_CLI_ARGUMENT_IDENTIFIER_CHAR << a.Alias() << std::endl;
    148         }
    149     }
    150 }
    151 
    152 TEST_CASE("CompleteCommand_FindRoot", "[complete]")
    153 {
    154     std::stringstream out, in;
    155     Context context{ out, in };
    156 
    157     CompleteCommand command{ "test" };
    158     context.Args.AddArg(Args::Type::Word, ""sv);
    159     context.Args.AddArg(Args::Type::CommandLine, "winget "sv);
    160     context.Args.AddArg(Args::Type::Position, "7"sv);
    161     command.Execute(context);
    162 
    163     // Create expected values
    164     RootCommand expectedCommand;
    165     std::stringstream expected;
    166     OutputAllSubCommands(expectedCommand, expected);
    167     OutputAllArgumentNames(expectedCommand, expected);
    168 
    169     REQUIRE(out.str() == expected.str());
    170 }
    171 
    172 TEST_CASE("CompleteCommand_FindSource", "[complete]")
    173 {
    174     std::stringstream out, in;
    175     Context context{ out, in };
    176 
    177     CompleteCommand command{ "test" };
    178     context.Args.AddArg(Args::Type::Word, ""sv);
    179     context.Args.AddArg(Args::Type::CommandLine, "winget source "sv);
    180     context.Args.AddArg(Args::Type::Position, "14"sv);
    181     command.Execute(context);
    182 
    183     // Create expected values
    184     SourceCommand expectedCommand{ "test" };
    185     std::stringstream expected;
    186     OutputAllSubCommands(expectedCommand, expected);
    187     OutputAllArgumentNames(expectedCommand, expected);
    188 
    189     REQUIRE(out.str() == expected.str());
    190 }
    191 
    192 TEST_CASE("CompleteCommand_FindSourceAdd", "[complete]")
    193 {
    194     std::stringstream out, in;
    195     Context context{ out, in };
    196 
    197     CompleteCommand command{ "test" };
    198     context.Args.AddArg(Args::Type::Word, ""sv);
    199     context.Args.AddArg(Args::Type::CommandLine, "winget source add "sv);
    200     context.Args.AddArg(Args::Type::Position, "18"sv);
    201     command.Execute(context);
    202 
    203     // Create expected values
    204     SourceAddCommand expectedCommand{ "test" };
    205     std::stringstream expected;
    206     OutputAllSubCommands(expectedCommand, expected);
    207     OutputAllArgumentNames(expectedCommand, expected);
    208 
    209     REQUIRE(out.str() == expected.str());
    210 }
    211 
    212 struct CompletionTestCommand : public Command
    213 {
    214     CompletionTestCommand() : Command("test", "") {}
    215     CompletionTestCommand(std::string_view name) : Command(name, "") {}
    216 
    217     std::vector<std::unique_ptr<Command>> GetCommands() const override
    218     {
    219         std::vector<std::unique_ptr<Command>> result;
    220 
    221         for (const auto& sc : SubCommandNames)
    222         {
    223             result.emplace_back(std::make_unique<CompletionTestCommand>(sc));
    224         }
    225 
    226         return result;
    227     }
    228 
    229     std::vector<Argument> GetArguments() const override
    230     {
    231         return Arguments;
    232     }
    233 
    234     CLI::Resource::LocString ShortDescription() const override { return {}; }
    235     CLI::Resource::LocString LongDescription() const override { return {}; }
    236 
    237     using Command::Complete;
    238 
    239     void Complete(Execution::Context& context, Execution::Args::Type valueType) const override
    240     {
    241         if (ArgumentValueCallback)
    242         {
    243             ArgumentValueCallback(context, valueType);
    244         }
    245     }
    246 
    247     std::vector<std::string> SubCommandNames;
    248     std::vector<Argument> Arguments;
    249     std::function<void(Context&, Execution::Args::Type)> ArgumentValueCallback;
    250 };
    251 
    252 struct CompletionTestContext
    253 {
    254     CompletionTestContext(std::string_view word, std::string_view commandLine, std::string_view position) :
    255         context(out, in)
    256     {
    257         context.Reporter.SetChannel(Execution::Reporter::Channel::Completion);
    258         context.Add<Data::CompletionData>(CompletionData{ word, commandLine, position });
    259     }
    260 
    261     std::stringstream out;
    262     std::stringstream in;
    263     Context context;
    264 };
    265 
    266 TEST_CASE("CommandComplete_Simple", "[complete]")
    267 {
    268     CompletionTestContext ctc{ "", "winget ", "7" };
    269 
    270     CompletionTestCommand command;
    271     command.SubCommandNames = { "test1", "test2" };
    272     command.Arguments = { Argument{ "arg1", 'a', Args::Type::Query, CLI::Resource::String::Done, ArgumentType::Standard } };
    273     command.ArgumentValueCallback = [&](Context&, Execution::Args::Type) { FAIL("No argument value should be requested"); };
    274     command.Complete(ctc.context);
    275 
    276     // Create expected values
    277     std::stringstream expected;
    278     OutputAllSubCommands(command, expected);
    279     OutputAllArgumentNames(command, expected);
    280 
    281     REQUIRE(ctc.out.str() == expected.str());
    282 }
    283 
    284 TEST_CASE("CommandComplete_PartialCommandMatch", "[complete]")
    285 {
    286     CompletionTestContext ctc{ "cart", "winget cart", "11" };
    287 
    288     CompletionTestCommand command;
    289     command.SubCommandNames = { "car", "cart", "cartesian", "carpet" };
    290     command.ArgumentValueCallback = [&](Context&, Execution::Args::Type) { FAIL("No argument value should be requested"); };
    291     command.Complete(ctc.context);
    292 
    293     // Create expected values
    294     std::stringstream expected;
    295     OutputAllSubCommands(command, expected, "cart");
    296     OutputAllArgumentNames(command, expected, "cart");
    297 
    298     REQUIRE(ctc.out.str() == expected.str());
    299 }
    300 
    301 TEST_CASE("CommandComplete_CommandsNotAllowed", "[complete]")
    302 {
    303     CompletionTestContext ctc{ "", "winget foobar ", "14" };
    304 
    305     CompletionTestCommand command;
    306     command.SubCommandNames = { "car", "cart", "cartesian", "carpet" };
    307     command.ArgumentValueCallback = [&](Context&, Execution::Args::Type) { FAIL("No argument value should be requested"); };
    308     command.Complete(ctc.context);
    309 
    310     // Create expected values
    311     std::stringstream expected;
    312     OutputAllArgumentNames(command, expected);
    313 
    314     REQUIRE(ctc.out.str() == expected.str());
    315 }
    316 
    317 TEST_CASE("CommandComplete_Routing1", "[complete]")
    318 {
    319     CompletionTestContext ctc{ "", "winget --arg1 ", "14" };
    320 
    321     CompletionTestCommand command;
    322     command.SubCommandNames = { "car", "cart", "cartesian", "carpet" };
    323     command.Arguments = {
    324         Argument{ "arg1", '1', Args::Type::Query, CLI::Resource::String::Done, ArgumentType::Standard },
    325         Argument{ "arg2", '2', Args::Type::Channel, CLI::Resource::String::Done, ArgumentType::Standard },
    326     };
    327     Args::Type argType = static_cast<Args::Type>(-1);
    328     command.ArgumentValueCallback = [&](Context&, Execution::Args::Type type) { argType = type; };
    329     command.Complete(ctc.context);
    330 
    331     // Create expected values
    332     std::stringstream expected;
    333 
    334     REQUIRE(ctc.out.str() == expected.str());
    335     REQUIRE(argType == command.Arguments[0].ExecArgType());
    336 }
    337 
    338 TEST_CASE("CommandComplete_Routing2", "[complete]")
    339 {
    340     CompletionTestContext ctc{ "", "winget --arg2 ", "14" };
    341 
    342     CompletionTestCommand command;
    343     command.SubCommandNames = { "car", "cart", "cartesian", "carpet" };
    344     command.Arguments = {
    345         Argument{ "arg1", '1', Args::Type::Query, CLI::Resource::String::Done, ArgumentType::Standard },
    346         Argument{ "arg2", '2', Args::Type::Channel, CLI::Resource::String::Done, ArgumentType::Standard },
    347     };
    348     Args::Type argType = static_cast<Args::Type>(-1);
    349     command.ArgumentValueCallback = [&](Context&, Execution::Args::Type type) { argType = type; };
    350     command.Complete(ctc.context);
    351 
    352     // Create expected values
    353     std::stringstream expected;
    354 
    355     REQUIRE(ctc.out.str() == expected.str());
    356     REQUIRE(argType == command.Arguments[1].ExecArgType());
    357 }
    358 
    359 TEST_CASE("CommandComplete_PositionalRouting", "[complete]")
    360 {
    361     CompletionTestContext ctc{ "", "winget ", "7" };
    362 
    363     CompletionTestCommand command;
    364     command.SubCommandNames = { "car", "cart", "cartesian", "carpet" };
    365     command.Arguments = {
    366         Argument{ "arg1", '1', Args::Type::Query, CLI::Resource::String::Done, ArgumentType::Standard },
    367         Argument{ "arg2", '2', Args::Type::Channel, CLI::Resource::String::Done, ArgumentType::Positional },
    368     };
    369     Args::Type argType = static_cast<Args::Type>(-1);
    370     command.ArgumentValueCallback = [&](Context&, Execution::Args::Type type) { argType = type; };
    371     command.Complete(ctc.context);
    372 
    373     // Create expected values
    374     std::stringstream expected;
    375     OutputAllSubCommands(command, expected);
    376     OutputAllArgumentNames(command, expected);
    377 
    378     REQUIRE(ctc.out.str() == expected.str());
    379     REQUIRE(argType == command.Arguments[1].ExecArgType());
    380 }
    381 
    382 TEST_CASE("CommandComplete_PositionalRoutingAfterArgs", "[complete]")
    383 {
    384     CompletionTestContext ctc{ "", "winget --arg1 value ", "20" };
    385 
    386     CompletionTestCommand command;
    387     command.SubCommandNames = { "car", "cart", "cartesian", "carpet" };
    388     command.Arguments = {
    389         Argument{ "arg1", '1', Args::Type::Query, CLI::Resource::String::Done, ArgumentType::Standard },
    390         Argument{ "arg2", '2', Args::Type::Channel, CLI::Resource::String::Done, ArgumentType::Positional },
    391     };
    392     Args::Type argType = static_cast<Args::Type>(-1);
    393     command.ArgumentValueCallback = [&](Context&, Execution::Args::Type type) { argType = type; };
    394     command.Complete(ctc.context);
    395 
    396     // Create expected values
    397     std::stringstream expected;
    398     OutputAllArgumentNames(command, expected);
    399 
    400     REQUIRE(ctc.out.str() == expected.str());
    401     REQUIRE(argType == command.Arguments[1].ExecArgType());
    402 }
    403 
    404 TEST_CASE("CommandComplete_PositionalRoutingAfterDoubleDash", "[complete]")
    405 {
    406     CompletionTestContext ctc{ "", "winget -- ", "10" };
    407 
    408     CompletionTestCommand command;
    409     command.SubCommandNames = { "car", "cart", "cartesian", "carpet" };
    410     command.Arguments = {
    411         Argument{ "arg1", '1', Args::Type::Query, CLI::Resource::String::Done, ArgumentType::Standard },
    412         Argument{ "arg2", '2', Args::Type::Channel, CLI::Resource::String::Done, ArgumentType::Positional },
    413     };
    414     Args::Type argType = static_cast<Args::Type>(-1);
    415     command.ArgumentValueCallback = [&](Context&, Execution::Args::Type type) { argType = type; };
    416     command.Complete(ctc.context);
    417 
    418     // Create expected values
    419     std::stringstream expected;
    420 
    421     REQUIRE(ctc.out.str() == expected.str());
    422     REQUIRE(argType == command.Arguments[1].ExecArgType());
    423 }
    424 
    425 TEST_CASE("CommandComplete_ArgNamesAfterDash", "[complete]")
    426 {
    427     CompletionTestContext ctc{ "-", "winget -", "8" };
    428 
    429     CompletionTestCommand command;
    430     command.SubCommandNames = { "car", "cart", "cartesian", "carpet" };
    431     command.Arguments = {
    432         Argument{ "arg1", '1', Args::Type::Query, CLI::Resource::String::Done, ArgumentType::Standard },
    433         Argument{ "arg2", '2', Args::Type::Channel, CLI::Resource::String::Done, ArgumentType::Positional },
    434     };
    435     command.ArgumentValueCallback = [&](Context&, Execution::Args::Type) { FAIL("No argument value should be requested"); };
    436     command.Complete(ctc.context);
    437 
    438     // Create expected values
    439     std::stringstream expected;
    440     OutputAllArgumentNames(command, expected);
    441 
    442     REQUIRE(ctc.out.str() == expected.str());
    443 }
    444 
    445 TEST_CASE("CommandComplete_AliasNames", "[complete]")
    446 {
    447     CompletionTestContext ctc{ "-a", "winget -a", "9" };
    448 
    449     CompletionTestCommand command;
    450     command.SubCommandNames = { "car", "cart", "cartesian", "carpet" };
    451     command.Arguments = {
    452         Argument{ "arg1", '1', Args::Type::Query, CLI::Resource::String::Done, ArgumentType::Standard },
    453         Argument{ "arg2", '2', Args::Type::Channel, CLI::Resource::String::Done, ArgumentType::Positional },
    454     };
    455     command.ArgumentValueCallback = [&](Context&, Execution::Args::Type) { FAIL("No argument value should be requested"); };
    456     command.Complete(ctc.context);
    457 
    458     // Create expected values
    459     std::stringstream expected;
    460     OutputAllArgumentAliases(command, expected);
    461 
    462     REQUIRE(ctc.out.str() == expected.str());
    463 }
    464 
    465 TEST_CASE("CommandComplete_ArgNamesFilter", "[complete]")
    466 {
    467     CompletionTestContext ctc{ "--a", "winget --a", "10" };
    468 
    469     CompletionTestCommand command;
    470     command.SubCommandNames = { "car", "cart", "cartesian", "carpet" };
    471     command.Arguments = {
    472         Argument{ "arg1", '1', Args::Type::Query, CLI::Resource::String::Done, ArgumentType::Standard },
    473         Argument{ "arg2", '2', Args::Type::Channel, CLI::Resource::String::Done, ArgumentType::Positional },
    474         Argument{ "foo1", '2', Args::Type::Channel, CLI::Resource::String::Done, ArgumentType::Positional },
    475     };
    476     command.ArgumentValueCallback = [&](Context&, Execution::Args::Type) { FAIL("No argument value should be requested"); };
    477     command.Complete(ctc.context);
    478 
    479     // Create expected values
    480     std::stringstream expected;
    481     OutputAllArgumentNames(command, expected, "a");
    482 
    483     REQUIRE(ctc.out.str() == expected.str());
    484 }
    485 
    486 TEST_CASE("CommandComplete_IgnoreBadArgs", "[complete]")
    487 {
    488     CompletionTestContext ctc{ "", "winget foo bar --arg1 ", "22" };
    489 
    490     CompletionTestCommand command;
    491     command.SubCommandNames = { "car", "cart", "cartesian", "carpet" };
    492     command.Arguments = {
    493         Argument{ "arg1", '1', Args::Type::Query, CLI::Resource::String::Done, ArgumentType::Standard },
    494         Argument{ "arg2", '2', Args::Type::Channel, CLI::Resource::String::Done, ArgumentType::Standard },
    495     };
    496     Args::Type argType = static_cast<Args::Type>(-1);
    497     command.ArgumentValueCallback = [&](Context&, Execution::Args::Type type) { argType = type; };
    498     command.Complete(ctc.context);
    499 
    500     // Create expected values
    501     std::stringstream expected;
    502 
    503     REQUIRE(ctc.out.str() == expected.str());
    504     REQUIRE(argType == command.Arguments[0].ExecArgType());
    505 }
    506 
    507 TEST_CASE("CommandComplete_OtherArgsParsed", "[complete]")
    508 {
    509     CompletionTestContext ctc{ "", "winget --arg1 value1  --arg2 value2", "21" };
    510 
    511     CompletionTestCommand command;
    512     command.SubCommandNames = { "car", "cart", "cartesian", "carpet" };
    513     command.Arguments = {
    514         Argument{ "arg1", '1', Args::Type::Query, CLI::Resource::String::Done, ArgumentType::Standard },
    515         Argument{ "arg2", '2', Args::Type::Channel, CLI::Resource::String::Done, ArgumentType::Standard },
    516     };
    517     command.ArgumentValueCallback = [&](Context&, Execution::Args::Type) { FAIL("No argument value should be requested"); };
    518     command.Complete(ctc.context);
    519 
    520     // Create expected values
    521     std::stringstream expected;
    522     OutputAllArgumentNames(command, expected);
    523 
    524     REQUIRE(ctc.out.str() == expected.str());
    525     REQUIRE(ctc.context.Args.Contains(command.Arguments[0].ExecArgType()));
    526     REQUIRE(ctc.context.Args.GetArg(command.Arguments[0].ExecArgType()) == "value1");
    527     REQUIRE(ctc.context.Args.Contains(command.Arguments[1].ExecArgType()));
    528     REQUIRE(ctc.context.Args.GetArg(command.Arguments[1].ExecArgType()) == "value2");
    529 }
    530 
    531 TEST_CASE("CommandComplete_Complex", "[complete]")
    532 {
    533     CompletionTestContext ctc{ "", "winget foo --arg1 value1 bar junk --arg2 ", "41" };
    534 
    535     CompletionTestCommand command;
    536     command.SubCommandNames = { "car", "cart", "cartesian", "carpet" };
    537     command.Arguments = {
    538         Argument{ "arg1", '1', Args::Type::Query, CLI::Resource::String::Done, ArgumentType::Standard },
    539         Argument{ "arg2", '2', Args::Type::Channel, CLI::Resource::String::Done, ArgumentType::Standard },
    540     };
    541     Args::Type argType = static_cast<Args::Type>(-1);
    542     command.ArgumentValueCallback = [&](Context&, Execution::Args::Type type) { argType = type; };
    543     command.Complete(ctc.context);
    544 
    545     // Create expected values
    546     std::stringstream expected;
    547 
    548     REQUIRE(ctc.out.str() == expected.str());
    549     REQUIRE(argType == command.Arguments[1].ExecArgType());
    550     REQUIRE(ctc.context.Args.Contains(command.Arguments[0].ExecArgType()));
    551     REQUIRE(ctc.context.Args.GetArg(command.Arguments[0].ExecArgType()) == "value1");
    552 }