| // Copyright 2017-2020 The Verible Authors. |
| // |
| // 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. |
| |
| #include "common/util/subcommand.h" |
| |
| #include <iostream> |
| #include <sstream> |
| #include <string> |
| #include <vector> |
| |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| #include "absl/strings/match.h" |
| |
| namespace verible { |
| namespace { |
| |
| TEST(SubcommandRegistryTest, NoNewCommands) { |
| SubcommandRegistry registry; |
| const std::string command_list = registry.ListCommands(); |
| EXPECT_TRUE(absl::StrContains(command_list, "help")); |
| // Make sure the internal 'error' command is not shown in help. |
| EXPECT_FALSE(absl::StrContains(command_list, "error")); |
| } |
| |
| TEST(SubcommandRegistryTest, HelpNoArgsTest) { |
| SubcommandRegistry registry; |
| // Test built-in help command. |
| const SubcommandEntry& help(registry.GetSubcommandEntry("help")); |
| std::istringstream ins; |
| std::ostringstream outs, errs; |
| std::vector<char*> args; |
| const SubcommandArgsRange range(args.begin(), args.end()); |
| const auto status = help.main(range, ins, outs, errs); |
| EXPECT_TRUE(status.ok()) << "Unexpected error:\n" << status.message(); |
| EXPECT_TRUE(outs.str().empty()) << outs.str(); |
| EXPECT_TRUE(absl::StrContains(errs.str(), "available commands:")); |
| } |
| |
| TEST(SubcommandRegistryTest, HelpHelpCommand) { |
| SubcommandRegistry registry; |
| // Test built-in help command. |
| const SubcommandEntry& help(registry.GetSubcommandEntry("help")); |
| std::istringstream ins; |
| std::ostringstream outs, errs; |
| char arg[] = "help"; |
| std::vector<char*> args{arg}; |
| const SubcommandArgsRange range(args.begin(), args.end()); |
| |
| const auto status = help.main(range, ins, outs, errs); |
| EXPECT_TRUE(status.ok()) << "Unexpected error:\n" << status.message(); |
| EXPECT_TRUE(outs.str().empty()) << outs.str(); |
| EXPECT_TRUE(absl::StrContains(errs.str(), "Prints command help.")); |
| } |
| |
| static const SubcommandEntry fizz_func{ |
| [](const SubcommandArgsRange, std::istream&, std::ostream& outs, |
| std::ostream&) { |
| outs << 42; |
| return absl::OkStatus(); |
| }, |
| "fizz does almost nothing", |
| true, // public |
| }; |
| |
| TEST(SubcommandRegistryTest, RegisterCommandPublicOk) { |
| SubcommandRegistry registry; |
| { |
| const auto status = registry.RegisterCommand("fizz", fizz_func); |
| EXPECT_TRUE(status.ok()) << "Unexpected error:\n" << status.message(); |
| EXPECT_TRUE(absl::StrContains(registry.ListCommands(), "fizz")); |
| } |
| |
| std::vector<char*> args; |
| const SubcommandArgsRange range(args.begin(), args.end()); |
| const SubcommandEntry& fizz_entry(registry.GetSubcommandEntry("fizz")); |
| |
| std::istringstream ins; |
| std::ostringstream outs, errs; |
| const auto status = fizz_entry.main(range, ins, outs, errs); |
| EXPECT_TRUE(status.ok()) << "Unexpected error:\n" << status.message(); |
| EXPECT_EQ(outs.str(), "42"); |
| } |
| |
| static const SubcommandEntry buzz_func{ |
| [](const SubcommandArgsRange, std::istream&, std::ostream& outs, |
| std::ostream&) { |
| outs << 99; |
| return absl::OkStatus(); |
| }, |
| "buzz does almost nothing", |
| false, // hidden |
| }; |
| |
| TEST(SubcommandRegistryTest, RegisterCommandHiddenOk) { |
| SubcommandRegistry registry; |
| { |
| const auto status = registry.RegisterCommand("buzz", buzz_func); |
| EXPECT_TRUE(status.ok()) << "Unexpected error:\n" << status.message(); |
| EXPECT_FALSE(absl::StrContains(registry.ListCommands(), "buzz")); |
| } |
| |
| std::vector<char*> args; |
| const SubcommandArgsRange range(args.begin(), args.end()); |
| const SubcommandEntry& buzz_entry(registry.GetSubcommandEntry("buzz")); |
| |
| std::istringstream ins; |
| std::ostringstream outs, errs; |
| const auto status = buzz_entry.main(range, ins, outs, errs); |
| EXPECT_TRUE(status.ok()) << "Unexpected error:\n" << status.message(); |
| EXPECT_EQ(outs.str(), "99"); |
| } |
| |
| TEST(SubcommandRegistryTest, RegisterCommandErrorAlreadyRegistered) { |
| SubcommandRegistry registry; |
| // "help" is already a registered command |
| const auto status = registry.RegisterCommand("help", fizz_func); |
| EXPECT_FALSE(status.ok()); |
| EXPECT_TRUE( |
| absl::StrContains(status.message(), "has already been registered")); |
| } |
| |
| TEST(SubcommandRegistryTest, RegisterCommandMultipleCommands) { |
| SubcommandRegistry registry; |
| { |
| { |
| const auto status = registry.RegisterCommand("buzz", buzz_func); |
| EXPECT_TRUE(status.ok()) << "Unexpected error:\n" << status.message(); |
| } |
| { |
| const auto status = registry.RegisterCommand("fizz", fizz_func); |
| EXPECT_TRUE(status.ok()) << "Unexpected error:\n" << status.message(); |
| } |
| const std::string command_list = registry.ListCommands(); |
| EXPECT_TRUE(absl::StrContains(command_list, "fizz")); |
| EXPECT_FALSE(absl::StrContains(command_list, "buzz")); |
| } |
| |
| // Run each subcommand once. |
| std::vector<char*> args; |
| const SubcommandArgsRange range(args.begin(), args.end()); |
| { |
| const SubcommandEntry& fizz_entry(registry.GetSubcommandEntry("fizz")); |
| std::istringstream ins; |
| std::ostringstream outs, errs; |
| const auto status = fizz_entry.main(range, ins, outs, errs); |
| EXPECT_TRUE(status.ok()) << "Unexpected error:\n" << status.message(); |
| EXPECT_EQ(outs.str(), "42"); |
| } |
| { |
| const SubcommandEntry& buzz_entry(registry.GetSubcommandEntry("buzz")); |
| std::istringstream ins; |
| std::ostringstream outs, errs; |
| const auto status = buzz_entry.main(range, ins, outs, errs); |
| EXPECT_TRUE(status.ok()) << "Unexpected error:\n" << status.message(); |
| EXPECT_EQ(outs.str(), "99"); |
| } |
| } |
| |
| } // namespace |
| } // namespace verible |