NestedCommandLineAppTest.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. * Copyright 2015-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <folly/experimental/NestedCommandLineApp.h>
  17. #include <folly/Subprocess.h>
  18. #include <folly/experimental/io/FsUtil.h>
  19. #include <folly/portability/GTest.h>
  20. #include <glog/logging.h>
  21. namespace folly {
  22. namespace test {
  23. namespace {
  24. std::string getHelperPath() {
  25. const auto basename = "nested_command_line_app_test_helper";
  26. auto path = fs::executable_path();
  27. path.remove_filename() /= basename;
  28. if (!fs::exists(path)) {
  29. path = path.parent_path().parent_path() / basename / basename;
  30. }
  31. return path.string();
  32. }
  33. std::string callHelper(
  34. std::initializer_list<std::string> args,
  35. int expectedExitCode = 0,
  36. int stdoutFd = -1) {
  37. static std::string helperPath = getHelperPath();
  38. std::vector<std::string> allArgs;
  39. allArgs.reserve(args.size() + 1);
  40. allArgs.push_back(helperPath);
  41. allArgs.insert(allArgs.end(), args.begin(), args.end());
  42. Subprocess::Options options;
  43. if (stdoutFd != -1) {
  44. options.stdoutFd(stdoutFd);
  45. } else {
  46. options.pipeStdout();
  47. }
  48. options.pipeStderr();
  49. Subprocess proc(allArgs, options);
  50. auto p = proc.communicate();
  51. EXPECT_EQ(expectedExitCode, proc.wait().exitStatus());
  52. return p.first;
  53. }
  54. } // namespace
  55. TEST(ProgramOptionsTest, Errors) {
  56. callHelper({}, 1);
  57. callHelper({"--wtf", "foo"}, 1);
  58. callHelper({"qux"}, 1);
  59. callHelper({"--global-foo", "x", "foo"}, 1);
  60. }
  61. TEST(ProgramOptionsTest, Help) {
  62. // Not actually checking help output, just verifying that help doesn't fail
  63. callHelper({"--version"});
  64. callHelper({"--help"});
  65. callHelper({"--help", "foo"});
  66. callHelper({"--help", "bar"});
  67. callHelper({"--help", "--", "bar"});
  68. callHelper({"help"});
  69. callHelper({"help", "foo"});
  70. callHelper({"help", "bar"});
  71. // wrong command name
  72. callHelper({"--help", "qux"}, 1);
  73. callHelper({"help", "qux"}, 1);
  74. // anything after -- is parsed as arguments
  75. callHelper({"--", "help", "bar"}, 1);
  76. }
  77. TEST(ProgramOptionsTest, DevFull) {
  78. folly::File full("/dev/full", O_RDWR);
  79. callHelper({"--help"}, 1, full.fd());
  80. }
  81. TEST(ProgramOptionsTest, CutArguments) {
  82. // anything after -- is parsed as arguments
  83. EXPECT_EQ(
  84. "running foo\n"
  85. "foo global-foo 43\n"
  86. "foo local-foo 42\n"
  87. "foo arg b\n"
  88. "foo arg --local-foo\n"
  89. "foo arg 44\n"
  90. "foo arg a\n",
  91. callHelper(
  92. {"foo", "--global-foo", "43", "--", "b", "--local-foo", "44", "a"}));
  93. }
  94. TEST(ProgramOptionsTest, Success) {
  95. EXPECT_EQ(
  96. "running foo\n"
  97. "foo global-foo 42\n"
  98. "foo local-foo 42\n",
  99. callHelper({"foo"}));
  100. EXPECT_EQ(
  101. "running foo\n"
  102. "foo global-foo 43\n"
  103. "foo local-foo 44\n"
  104. "foo arg a\n"
  105. "foo arg b\n",
  106. callHelper({"--global-foo", "43", "foo", "--local-foo", "44", "a", "b"}));
  107. // Check that global flags can still be given after the command
  108. EXPECT_EQ(
  109. "running foo\n"
  110. "foo global-foo 43\n"
  111. "foo local-foo 44\n"
  112. "foo arg a\n"
  113. "foo arg b\n",
  114. callHelper({"foo", "--global-foo", "43", "--local-foo", "44", "a", "b"}));
  115. }
  116. TEST(ProgramOptionsTest, Aliases) {
  117. EXPECT_EQ(
  118. "running foo\n"
  119. "foo global-foo 43\n"
  120. "foo local-foo 44\n"
  121. "foo arg a\n"
  122. "foo arg b\n",
  123. callHelper({"--global-foo", "43", "bar", "--local-foo", "44", "a", "b"}));
  124. }
  125. TEST(ProgramOptionsTest, BuiltinCommand) {
  126. NestedCommandLineApp app;
  127. ASSERT_TRUE(app.isBuiltinCommand(NestedCommandLineApp::kHelpCommand.str()));
  128. ASSERT_TRUE(
  129. app.isBuiltinCommand(NestedCommandLineApp::kVersionCommand.str()));
  130. ASSERT_FALSE(app.isBuiltinCommand(
  131. NestedCommandLineApp::kHelpCommand.str() + "nonsense"));
  132. }
  133. } // namespace test
  134. } // namespace folly