Helper for writing nested command line apps
[folly.git] / folly / experimental / test / NestedCommandLineAppTest.cpp
diff --git a/folly/experimental/test/NestedCommandLineAppTest.cpp b/folly/experimental/test/NestedCommandLineAppTest.cpp
new file mode 100644 (file)
index 0000000..cdfcd31
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * 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 <folly/experimental/NestedCommandLineApp.h>
+
+#include <folly/Subprocess.h>
+#include <folly/experimental/io/FsUtil.h>
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+namespace folly { namespace test {
+
+namespace {
+
+std::string getHelperPath() {
+  auto path = fs::executable_path();
+  path.remove_filename() /= "nested_command_line_app_test_helper";
+  return path.native();
+}
+
+std::string callHelper(std::initializer_list<std::string> args,
+                       int expectedExitCode = 0,
+                       int stdoutFd = -1) {
+  static std::string helperPath = getHelperPath();
+
+  std::vector<std::string> allArgs;
+  allArgs.reserve(args.size() + 1);
+  allArgs.push_back(helperPath);
+  allArgs.insert(allArgs.end(), args.begin(), args.end());
+
+  Subprocess::Options options;
+  if (stdoutFd != -1) {
+    options.stdout(stdoutFd);
+  } else {
+    options.pipeStdout();
+  }
+  options.pipeStderr();
+
+  Subprocess proc(allArgs, options);
+  auto p = proc.communicate();
+  EXPECT_EQ(expectedExitCode, proc.wait().exitStatus());
+
+  return p.first;
+}
+
+}  // namespace
+
+TEST(ProgramOptionsTest, Errors) {
+  callHelper({}, 1);
+  callHelper({"--wtf", "foo"}, 1);
+  callHelper({"qux"}, 1);
+  callHelper({"--global-foo", "x", "foo"}, 1);
+}
+
+TEST(ProgramOptionsTest, Help) {
+  // Not actually checking help output, just verifying that help doesn't fail
+  callHelper({"--version"});
+  callHelper({"--help"});
+  callHelper({"--help", "foo"});
+  callHelper({"--help", "bar"});
+  callHelper({"help"});
+  callHelper({"help", "foo"});
+  callHelper({"help", "bar"});
+
+  // wrong command name
+  callHelper({"--help", "qux"}, 1);
+  callHelper({"help", "qux"}, 1);
+}
+
+TEST(ProgramOptionsTest, DevFull) {
+  folly::File full("/dev/full", O_RDWR);
+  callHelper({"--help"}, 1, full.fd());
+}
+
+TEST(ProgramOptionsTest, Success) {
+  EXPECT_EQ(
+      "running foo\n"
+      "foo global-foo 42\n"
+      "foo local-foo 42\n",
+      callHelper({"foo"}));
+
+  EXPECT_EQ(
+      "running foo\n"
+      "foo global-foo 43\n"
+      "foo local-foo 44\n"
+      "foo arg a\n"
+      "foo arg b\n",
+      callHelper({"--global-foo", "43", "foo", "--local-foo", "44",
+                  "a", "b"}));
+
+  // Check that global flags can still be given after the command
+  EXPECT_EQ(
+      "running foo\n"
+      "foo global-foo 43\n"
+      "foo local-foo 44\n"
+      "foo arg a\n"
+      "foo arg b\n",
+      callHelper({"foo", "--global-foo", "43", "--local-foo", "44",
+                 "a", "b"}));
+}
+
+TEST(ProgramOptionsTest, Aliases) {
+  EXPECT_EQ(
+      "running foo\n"
+      "foo global-foo 43\n"
+      "foo local-foo 44\n"
+      "foo arg a\n"
+      "foo arg b\n",
+      callHelper({"--global-foo", "43", "bar", "--local-foo", "44",
+                  "a", "b"}));
+}
+
+}}  // namespaces