* @brief Helper namespace for Cynara's command-line options parsing
*/
+#include <cstdlib>
#include <getopt.h>
+#include <grp.h>
#include <iostream>
+#include <pwd.h>
#include <sstream>
#include "CmdlineParser.h"
return os << static_cast<char>(opt);
}
-bool handleCmdlineOptions(int argc, char * const *argv) {
+struct CmdLineOptions handleCmdlineOptions(int argc, char * const *argv) {
const std::string execName(argv[0]);
std::stringstream shortOpts;
- shortOpts << ":" << CmdlineOpt::Help << CmdlineOpt::Version;
+ shortOpts << ":"
+ << CmdlineOpt::Help
+ << CmdlineOpt::Version
+ << CmdlineOpt::Daemon
+ << CmdlineOpt::Mask << ":"
+ << CmdlineOpt::User << ":"
+ << CmdlineOpt::Group << ":";
const struct option longOpts[] = {
- { "help", no_argument, NULL, CmdlineOpt::Help },
- { "version", no_argument, NULL, CmdlineOpt::Version },
+ { "help", no_argument, NULL, CmdlineOpt::Help },
+ { "version", no_argument, NULL, CmdlineOpt::Version },
+ { "daemon", no_argument, NULL, CmdlineOpt::Daemon },
+ { "mask", required_argument, NULL, CmdlineOpt::Mask },
+ { "user", required_argument, NULL, CmdlineOpt::User },
+ { "group", required_argument, NULL, CmdlineOpt::Group },
{ NULL, 0, NULL, 0 }
};
+ struct CmdLineOptions ret = {.m_error = false,
+ .m_exit = false,
+ .m_daemon = false,
+ .m_mask = static_cast<mode_t>(-1),
+ .m_uid = static_cast<uid_t>(-1),
+ .m_gid = static_cast<gid_t>(-1) };
optind = 0; // On entry to `getopt', zero means this is the first call; initialize.
int opt;
switch (opt) {
case CmdlineOpt::Help:
printHelp(execName);
- return true;
+ ret.m_error = false;
+ ret.m_exit = true;
+ return ret;
case CmdlineOpt::Version:
printVersion();
- return true;
+ ret.m_error = false;
+ ret.m_exit = true;
+ return ret;
+ case CmdlineOpt::Daemon:
+ ret.m_daemon = true;
+ break;
+ case CmdlineOpt::Mask:
+ ret.m_mask = getMask(optarg);
+ if (ret.m_mask == static_cast<mode_t>(-1)) {
+ printInvalidParam(execName, optarg);
+ ret.m_error = true;
+ ret.m_exit = true;
+ return ret;
+ }
+ break;
+ case CmdlineOpt::User:
+ ret.m_uid = getUid(optarg);
+ if (ret.m_uid == static_cast<uid_t>(-1)) {
+ printInvalidParam(execName, optarg);
+ ret.m_error = true;
+ ret.m_exit = true;
+ return ret;
+ }
+ break;
+ case CmdlineOpt::Group:
+ ret.m_gid = getGid(optarg);
+ if (ret.m_gid == static_cast<gid_t>(-1)) {
+ printInvalidParam(execName, optarg);
+ ret.m_error = true;
+ ret.m_exit = true;
+ return ret;
+ }
+ break;
+ case ':': // Missing argument
+ ret.m_error = true;
+ ret.m_exit = true;
+ switch (optopt) {
+ case CmdlineOpt::Mask:
+ case CmdlineOpt::User:
+ case CmdlineOpt::Group:
+ printMissingArgument(execName, argv[optind - 1]);
+ return ret;
+ }
+ //intentional fall to Unknown option
case '?': // Unknown option
default:
- printUnknownOption(execName);
- return false;
+ printUnknownOption(execName, argv[optind - 1]);
+ ret.m_error = true;
+ ret.m_exit = true;
+ return ret;
}
}
- printNoOptions(execName);
- return false;
+ return ret;
}
void printHelp(const std::string &execName) {
std::cout << "Usage: " << execName << " [OPTIONS]" << std::endl << std::endl;
- std::cout << " -V, --version print version of " << execName << " and exit"
- << std::endl;
- std::cout << " -h, --help print this help message and exit" << std::endl;
+ std::cout << "Information mode options [program exits after printing information]:" << std::endl;
+ std::cout << " -V, --version print version of " << execName << " and exit"
+ << std::endl;
+ std::cout << " -h, --help print this help message and exit" << std::endl;
+ std::cout << "Normal work mode options:" << std::endl;
+ std::cout << " -d, --daemon daemonize "
+ "[by default " << execName << " does not daemonize]" << std::endl;
+ std::cout << " -m, --mask=MASK set umask to MASK "
+ "[by default no umask is set]" << std::endl;
+ std::cout << " -u, --user=USER change user to USER "
+ "[by default uid is not changed]" << std::endl;
+ std::cout << " -g, --group=GROUP change group to GROUP "
+ "[by default gid is not changed]" << std::endl;
}
void printVersion(void) {
std::cout << std::string(CYNARA_VERSION) << std::endl;
}
-void printUnknownOption(const std::string &execName) {
- std::cerr << "Unknown option" << std::endl;
+void printUnknownOption(const std::string &execName, const std::string &option) {
+ std::cerr << "Unknown option: " << option << std::endl;
printHelp(execName);
}
-void printNoOptions(const std::string &execName) {
- std::cerr << "No options given" << std::endl;
+void printInvalidParam(const std::string &execName, const std::string ¶m) {
+ std::cerr << "Invalid param: " << param << std::endl;
printHelp(execName);
}
+void printMissingArgument(const std::string &execName, const std::string &option) {
+ std::cerr << "Missing argument for option: " << option << std::endl;
+ printHelp(execName);
+}
+
+mode_t getMask(const char *mask) {
+ mode_t ret = static_cast<mode_t>(-1);
+ if (!mask)
+ return ret;
+ try {
+ ret = static_cast<mode_t>(std::stoi(mask, 0, 0));
+ } catch (...) {
+ }
+ return ret;
+}
+
+uid_t getUid(const char *user) {
+ uid_t ret = static_cast<uid_t>(-1);
+ if (!user)
+ return ret;
+ try {
+ ret = static_cast<uid_t>(std::stoi(user));
+ } catch (...) {
+ struct passwd *pwd = getpwnam(user);
+ if (pwd)
+ ret = pwd->pw_uid;
+ }
+ return ret;
+}
+
+gid_t getGid(const char *group) {
+ gid_t ret = static_cast<gid_t>(-1);
+ if (!group)
+ return ret;
+ try {
+ ret = static_cast<gid_t>(std::stoi(group));
+ } catch (...) {
+ struct group *grp = getgrnam(group);
+ if (grp)
+ ret = grp->gr_gid;
+ }
+ return ret;
+}
+
} /* namespace CmdlineOpts */
} /* namespace Cynara */
namespace {
const std::string execName("./cynara");
-const std::string helpMessage("Usage: " + execName + " [OPTIONS]\n\n"
- " -V, --version print version of ./cynara and exit\n"
- " -h, --help print this help message and exit\n");
+const std::string helpMessage(
+ "Usage: " + execName + " [OPTIONS]\n\n"
+ "Information mode options [program exits after printing information]:\n"
+ " -V, --version print version of " + execName + " and exit\n"
+ " -h, --help print this help message and exit\n"
+ "Normal work mode options:\n"
+ " -d, --daemon daemonize "
+ "[by default " + execName + " does not daemonize]\n"
+ " -m, --mask=MASK set umask to MASK "
+ "[by default no umask is set]\n"
+ " -u, --user=USER change user to USER "
+ "[by default uid is not changed]\n"
+ " -g, --group=GROUP change group to GROUP "
+ "[by default gid is not changed]\n");
} // namespace
prepare_argv({ execName, opt });
SCOPED_TRACE(opt);
- const auto handlingSuccess = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
getOutput(out, err);
- ASSERT_TRUE(handlingSuccess);
+ ASSERT_FALSE(options.m_error);
+ ASSERT_TRUE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, static_cast<uid_t>(-1));
+ ASSERT_EQ(options.m_gid, static_cast<gid_t>(-1));
ASSERT_EQ(helpMessage, out);
ASSERT_TRUE(err.empty());
}
prepare_argv({ execName, opt });
SCOPED_TRACE(opt);
- const auto handlingSuccess = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
getOutput(out, err);
- ASSERT_TRUE(handlingSuccess);
+ ASSERT_FALSE(options.m_error);
+ ASSERT_TRUE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, static_cast<uid_t>(-1));
+ ASSERT_EQ(options.m_gid, static_cast<gid_t>(-1));
ASSERT_EQ(std::string(CYNARA_VERSION) + "\n", out);
ASSERT_TRUE(err.empty());
}
prepare_argv({ execName, badOpt });
SCOPED_TRACE(badOpt);
- const auto handlingSuccess = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
getOutput(out, err);
- ASSERT_FALSE(handlingSuccess);
+ ASSERT_TRUE(options.m_error);
+ ASSERT_TRUE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, static_cast<uid_t>(-1));
+ ASSERT_EQ(options.m_gid, static_cast<gid_t>(-1));
ASSERT_EQ(helpMessage, out);
- ASSERT_EQ("Unknown option\n", err);
+ ASSERT_EQ(std::string("Unknown option: ") + badOpt + "\n", err);
}
}
/**
- * @brief Verify if passing no options to commandline handler returns error message
+ * @brief Verify if passing no options to commandline handler succeeds
* @test Expected result:
- * - call handler indicates failure
- * - help message in output stream
- * - error message in error stream
+ * - call handler indicates success
+ * - empty output stream
+ * - empty error stream
*/
TEST_F(CynaraCommandlineTest, noOption) {
std::string err;
clearOutput();
prepare_argv({ execName });
- const auto handlingSuccess = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
getOutput(out, err);
- ASSERT_FALSE(handlingSuccess);
- ASSERT_EQ(helpMessage, out);
- ASSERT_EQ("No options given\n", err);
+ ASSERT_FALSE(options.m_error);
+ ASSERT_FALSE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, static_cast<uid_t>(-1));
+ ASSERT_EQ(options.m_gid, static_cast<gid_t>(-1));
+ ASSERT_TRUE(out.empty());
+ ASSERT_TRUE(err.empty());
+}
+
+/**
+ * @brief Verify if passing daemon option to commandline succeeds
+ * @test Expected result:
+ * - call handler indicates success
+ * - empty output stream
+ * - empty error stream
+ */
+TEST_F(CynaraCommandlineTest, daemonOption) {
+ std::string err;
+ std::string out;
+
+ for (const auto &daemonOpt : { "-d", "--daemon" }) {
+ clearOutput();
+ prepare_argv({ execName, daemonOpt });
+
+ SCOPED_TRACE(daemonOpt);
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ getOutput(out, err);
+
+ ASSERT_FALSE(options.m_error);
+ ASSERT_FALSE(options.m_exit);
+ ASSERT_TRUE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, static_cast<uid_t>(-1));
+ ASSERT_EQ(options.m_gid, static_cast<gid_t>(-1));
+ ASSERT_TRUE(out.empty());
+ ASSERT_TRUE(err.empty());
+ }
+}
+
+/**
+ * @brief Verify if passing mask option to commandline succeeds
+ * @test Expected result:
+ * - call handler indicates success
+ * - empty output stream
+ * - empty error stream
+ */
+TEST_F(CynaraCommandlineTest, maskOption) {
+ std::string err;
+ std::string out;
+
+ std::string maskParam("0666");
+
+ for (const auto &maskOpt : { "-m", "--mask" }) {
+ clearOutput();
+ prepare_argv({ execName, maskOpt, maskParam});
+
+ SCOPED_TRACE(maskOpt);
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ getOutput(out, err);
+
+ ASSERT_FALSE(options.m_error);
+ ASSERT_FALSE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, 0666);
+ ASSERT_EQ(options.m_uid, static_cast<uid_t>(-1));
+ ASSERT_EQ(options.m_gid, static_cast<gid_t>(-1));
+ ASSERT_TRUE(out.empty());
+ ASSERT_TRUE(err.empty());
+ }
+}
+
+/**
+ * @brief Verify if passing invalid mask option to commandline fails
+ * @test Expected result:
+ * - call handler indicates failure
+ * - help message in output stream
+ * - error message in error stream
+ */
+TEST_F(CynaraCommandlineTest, maskOptionInvalid) {
+ std::string err;
+ std::string out;
+
+ std::string maskParam("MASK");
+
+ for (const auto &maskOpt : { "-m", "--mask" }) {
+ clearOutput();
+ prepare_argv({ execName, maskOpt, maskParam});
+
+ SCOPED_TRACE(maskOpt);
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ getOutput(out, err);
+
+ ASSERT_TRUE(options.m_error);
+ ASSERT_TRUE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, static_cast<uid_t>(-1));
+ ASSERT_EQ(options.m_gid, static_cast<gid_t>(-1));
+ ASSERT_EQ(helpMessage, out);
+ ASSERT_EQ("Invalid param: MASK\n", err);
+ }
+}
+
+/**
+ * @brief Verify if passing no mask option to commandline fails
+ * @test Expected result:
+ * - call handler indicates failure
+ * - help message in output stream
+ * - error message in error stream
+ */
+TEST_F(CynaraCommandlineTest, maskOptionNoParam) {
+ std::string err;
+ std::string out;
+
+ for (const auto &maskOpt : { "-m", "--mask" }) {
+ clearOutput();
+ prepare_argv({ execName, maskOpt});
+
+ SCOPED_TRACE(maskOpt);
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ getOutput(out, err);
+
+ ASSERT_TRUE(options.m_error);
+ ASSERT_TRUE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, static_cast<uid_t>(-1));
+ ASSERT_EQ(options.m_gid, static_cast<gid_t>(-1));
+ ASSERT_EQ(helpMessage, out);
+ ASSERT_EQ(std::string("Missing argument for option: ") + maskOpt + "\n", err);
+ }
+}
+
+/**
+ * @brief Verify if passing user option to commandline succeeds
+ * @test Expected result:
+ * - call handler indicates success
+ * - empty output stream
+ * - empty error stream
+ */
+TEST_F(CynaraCommandlineTest, userOptionName) {
+ std::string err;
+ std::string out;
+
+ std::string userParam("root");
+
+ for (const auto &userOpt : { "-u", "--user" }) {
+ clearOutput();
+ prepare_argv({ execName, userOpt, userParam});
+
+ SCOPED_TRACE(userOpt);
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ getOutput(out, err);
+
+ ASSERT_FALSE(options.m_error);
+ ASSERT_FALSE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, 0);
+ ASSERT_EQ(options.m_gid, static_cast<gid_t>(-1));
+ ASSERT_TRUE(out.empty());
+ ASSERT_TRUE(err.empty());
+ }
+}
+
+/**
+ * @brief Verify if passing user option to commandline succeeds
+ * @test Expected result:
+ * - call handler indicates success
+ * - empty output stream
+ * - empty error stream
+ */
+TEST_F(CynaraCommandlineTest, userOptionUid) {
+ std::string err;
+ std::string out;
+
+ std::string userParam("1234");
+
+ for (const auto &userOpt : { "-u", "--user" }) {
+ clearOutput();
+ prepare_argv({ execName, userOpt, userParam});
+
+ SCOPED_TRACE(userOpt);
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ getOutput(out, err);
+
+ ASSERT_FALSE(options.m_error);
+ ASSERT_FALSE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, 1234);
+ ASSERT_EQ(options.m_gid, static_cast<gid_t>(-1));
+ ASSERT_TRUE(out.empty());
+ ASSERT_TRUE(err.empty());
+ }
+}
+
+/**
+ * @brief Verify if passing invalid user option to commandline fails
+ * @test Expected result:
+ * - call handler indicates success
+ * - help message in output stream
+ * - error message in error stream
+ */
+TEST_F(CynaraCommandlineTest, userOptionInvalid) {
+ std::string err;
+ std::string out;
+
+ std::string userParam("UserThatDoNotExist");
+
+ for (const auto &userOpt : { "-u", "--user" }) {
+ clearOutput();
+ prepare_argv({ execName, userOpt, userParam});
+
+ SCOPED_TRACE(userOpt);
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ getOutput(out, err);
+
+ ASSERT_TRUE(options.m_error);
+ ASSERT_TRUE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, static_cast<uid_t>(-1));
+ ASSERT_EQ(options.m_gid, static_cast<gid_t>(-1));
+ ASSERT_EQ(helpMessage, out);
+ ASSERT_EQ("Invalid param: UserThatDoNotExist\n", err);
+ }
+}
+
+/**
+ * @brief Verify if passing no user option to commandline fails
+ * @test Expected result:
+ * - call handler indicates failure
+ * - help message in output stream
+ * - error message in error stream
+ */
+TEST_F(CynaraCommandlineTest, userOptionNoParam) {
+ std::string err;
+ std::string out;
+
+ for (const auto &userOpt : { "-u", "--user" }) {
+ clearOutput();
+ prepare_argv({ execName, userOpt});
+
+ SCOPED_TRACE(userOpt);
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ getOutput(out, err);
+
+ ASSERT_TRUE(options.m_error);
+ ASSERT_TRUE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, static_cast<uid_t>(-1));
+ ASSERT_EQ(options.m_gid, static_cast<gid_t>(-1));
+ ASSERT_EQ(helpMessage, out);
+ ASSERT_EQ(std::string("Missing argument for option: ") + userOpt + "\n", err);
+ }
+}
+
+/**
+ * @brief Verify if passing group option to commandline succeeds
+ * @test Expected result:
+ * - call handler indicates success
+ * - empty output stream
+ * - empty error stream
+ */
+TEST_F(CynaraCommandlineTest, groupOptionName) {
+ std::string err;
+ std::string out;
+
+ std::string groupParam("root");
+
+ for (const auto &groupOpt : { "-g", "--group" }) {
+ clearOutput();
+ prepare_argv({ execName, groupOpt, groupParam});
+
+ SCOPED_TRACE(groupOpt);
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ getOutput(out, err);
+
+ ASSERT_FALSE(options.m_error);
+ ASSERT_FALSE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, static_cast<uid_t>(-1));
+ ASSERT_EQ(options.m_gid, 0);
+ ASSERT_TRUE(out.empty());
+ ASSERT_TRUE(err.empty());
+ }
+}
+
+/**
+ * @brief Verify if passing group option to commandline succeeds
+ * @test Expected result:
+ * - call handler indicates success
+ * - empty output stream
+ * - empty error stream
+ */
+TEST_F(CynaraCommandlineTest, groupOptionGid) {
+ std::string err;
+ std::string out;
+
+ std::string groupParam("1234");
+
+ for (const auto &groupOpt : { "-g", "--group" }) {
+ clearOutput();
+ prepare_argv({ execName, groupOpt, groupParam});
+
+ SCOPED_TRACE(groupOpt);
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ getOutput(out, err);
+
+ ASSERT_FALSE(options.m_error);
+ ASSERT_FALSE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, static_cast<uid_t>(-1));
+ ASSERT_EQ(options.m_gid, 1234);
+ ASSERT_TRUE(out.empty());
+ ASSERT_TRUE(err.empty());
+ }
+}
+
+/**
+ * @brief Verify if passing invalid group option to commandline fails
+ * @test Expected result:
+ * - call handler indicates success
+ * - help message in output stream
+ * - error message in error stream
+ */
+TEST_F(CynaraCommandlineTest, groupOptionInvalid) {
+ std::string err;
+ std::string out;
+
+ std::string groupParam("GroupThatDoNotExist");
+
+ for (const auto &groupOpt : { "-g", "--group" }) {
+ clearOutput();
+ prepare_argv({ execName, groupOpt, groupParam});
+
+ SCOPED_TRACE(groupOpt);
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ getOutput(out, err);
+
+ ASSERT_TRUE(options.m_error);
+ ASSERT_TRUE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, static_cast<uid_t>(-1));
+ ASSERT_EQ(options.m_gid, static_cast<gid_t>(-1));
+ ASSERT_EQ(helpMessage, out);
+ ASSERT_EQ("Invalid param: GroupThatDoNotExist\n", err);
+ }
+}
+
+/**
+ * @brief Verify if passing no group option to commandline fails
+ * @test Expected result:
+ * - call handler indicates failure
+ * - help message in output stream
+ * - error message in error stream
+ */
+TEST_F(CynaraCommandlineTest, groupOptionNoParam) {
+ std::string err;
+ std::string out;
+
+ for (const auto &groupOpt : { "-g", "--group" }) {
+ clearOutput();
+ prepare_argv({ execName, groupOpt});
+
+ SCOPED_TRACE(groupOpt);
+ const auto options = Parser::handleCmdlineOptions(this->argc(), this->argv());
+ getOutput(out, err);
+
+ ASSERT_TRUE(options.m_error);
+ ASSERT_TRUE(options.m_exit);
+ ASSERT_FALSE(options.m_daemon);
+ ASSERT_EQ(options.m_mask, static_cast<mode_t>(-1));
+ ASSERT_EQ(options.m_uid, static_cast<uid_t>(-1));
+ ASSERT_EQ(options.m_gid, static_cast<gid_t>(-1));
+ ASSERT_EQ(helpMessage, out);
+ ASSERT_EQ(std::string("Missing argument for option: ") + groupOpt + "\n", err);
+ }
}