|
|
@@ -9,13 +9,12 @@
|
|
|
|
|
|
#include "xcode_gtest_helper.h"
|
|
|
|
|
|
+using testing::NotNull;
|
|
|
+
|
|
|
namespace program {
|
|
|
struct ArgumentTestHelper {
|
|
|
- template <typename Impl> bool has_main(Impl const & args) const {
|
|
|
- return static_cast<bool>(args.main_callback);
|
|
|
- }
|
|
|
- template <typename Impl> int main(Impl const & args) const {
|
|
|
- return args.main_callback(args);
|
|
|
+ template <typename Impl> static int main(Impl const & args) {
|
|
|
+ return args.invoke();
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
@@ -24,11 +23,17 @@ template <typename T, size_t N> static T parse(char const * const (&argv)[N]) {
|
|
|
return T(N, argv);
|
|
|
}
|
|
|
|
|
|
-std::string g_type_name;
|
|
|
+program::detail::Any g_action;
|
|
|
|
|
|
template <typename Args, typename Action>
|
|
|
-int typed_main(Args const &, Action const &) {
|
|
|
- g_type_name = typeid(Action).name();
|
|
|
+int typed_main(Args const &, Action const & action) {
|
|
|
+ g_action = program::detail::Any(&action);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+template <typename Args, typename Action, typename SubAction>
|
|
|
+int typed_main(Args const &, Action const &, SubAction const & action) {
|
|
|
+ g_action = program::detail::Any(&action);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
@@ -42,6 +47,36 @@ struct Commit : program::Arguments<Commit> {
|
|
|
std::string message = option("message", 'm');
|
|
|
};
|
|
|
|
|
|
+class Push : public program::Arguments<Push> {
|
|
|
+public:
|
|
|
+ using Arguments::Arguments;
|
|
|
+ std::string remote = argument(0, "repository") = PROGRAM_DEFER(_remote());
|
|
|
+
|
|
|
+private:
|
|
|
+ std::string _remote() const;
|
|
|
+};
|
|
|
+
|
|
|
+struct SetUrl : program::Arguments<SetUrl> {
|
|
|
+ using Arguments::Arguments;
|
|
|
+ bool push = flag("push") = false;
|
|
|
+ std::string name = argument(0, "name");
|
|
|
+ std::string new_url = argument(1, "newurl");
|
|
|
+ std::string old_url = argument(2, "oldurl") = "";
|
|
|
+};
|
|
|
+
|
|
|
+struct Show : program::Arguments<Show> {
|
|
|
+ using Arguments::Arguments;
|
|
|
+ bool use_cached = flag('n') = false;
|
|
|
+};
|
|
|
+
|
|
|
+struct Remote : public program::Arguments<Remote> {
|
|
|
+ PROGRAM_ARGS_INVOKE_WITH_DEFAULT(show, show, set_url);
|
|
|
+
|
|
|
+ bool verbose = flag('v') = false;
|
|
|
+ SetUrl set_url = action("set-url");
|
|
|
+ Show show = action("show");
|
|
|
+};
|
|
|
+
|
|
|
struct Bad1 : program::Arguments<Bad1> {
|
|
|
using Arguments::Arguments;
|
|
|
|
|
|
@@ -57,14 +92,22 @@ struct Bad2 : program::Arguments<Bad2> {
|
|
|
};
|
|
|
|
|
|
struct Git : program::Arguments<Git> {
|
|
|
- using Arguments::Arguments;
|
|
|
+ PROGRAM_ARGS_INVOKE(commit, checkout, push, remote);
|
|
|
|
|
|
+ std::string pwd = option('C');
|
|
|
bool verbose = flag("verbose", 'v');
|
|
|
|
|
|
Commit commit = action("commit");
|
|
|
Checkout checkout = action("checkout");
|
|
|
+ Push push = action("push");
|
|
|
+ Remote remote = action("remote");
|
|
|
};
|
|
|
|
|
|
+std::string Push::_remote() const {
|
|
|
+ if (Git const * git = Arguments::parent<Git>()) { return git->pwd; }
|
|
|
+ return "";
|
|
|
+}
|
|
|
+
|
|
|
TEST(ActionTest, CannotMixActionAndArgument) {
|
|
|
EXPECT_THROW(Bad1(), program::ArgumentMixingError);
|
|
|
EXPECT_THROW(Bad2(), program::ArgumentMixingError);
|
|
|
@@ -74,8 +117,38 @@ TEST(ActionTest, CanRunWithMultipleActions) { EXPECT_NO_THROW(Git()); }
|
|
|
|
|
|
TEST(ActionTest, ActionIsRouted) {
|
|
|
Git git = parse<Git>({"", "-v", "commit", "-m", "this is a message"});
|
|
|
- program::ArgumentTestHelper helper;
|
|
|
- EXPECT_TRUE(helper.has_main(git));
|
|
|
- helper.main(git);
|
|
|
- EXPECT_THAT(g_type_name, typeid(Commit).name());
|
|
|
+ EXPECT_THAT(git.commit.message, "this is a message");
|
|
|
+}
|
|
|
+
|
|
|
+TEST(ActionTest, CanDiveIntoTypedMain) {
|
|
|
+ Git git = parse<Git>({"", "-v", "commit", "-m", "this is a message"});
|
|
|
+ program::ArgumentTestHelper::main(git);
|
|
|
+ EXPECT_THAT(g_action.get<Commit>(), NotNull());
|
|
|
+}
|
|
|
+
|
|
|
+TEST(ActionTest, CanFetchParentInfo) {
|
|
|
+ Git git = parse<Git>({"", "-C", "./submodules/X", "push"});
|
|
|
+ EXPECT_THAT(git.push.remote, "./submodules/X");
|
|
|
+}
|
|
|
+
|
|
|
+TEST(ActionTest, ReturnsFailureOnNoAction) {
|
|
|
+ Git git = parse<Git>({""});
|
|
|
+
|
|
|
+ EXPECT_THAT(program::ArgumentTestHelper::main(git), 1);
|
|
|
+}
|
|
|
+
|
|
|
+TEST(ActionTest, CanRecursivelyPerformActions) {
|
|
|
+ Git git = parse<Git>({"", "remote", "-v", "show", "-n"});
|
|
|
+ EXPECT_TRUE(git.remote.verbose);
|
|
|
+ EXPECT_TRUE(git.remote.show.use_cached);
|
|
|
+
|
|
|
+ program::ArgumentTestHelper::main(git);
|
|
|
+ EXPECT_THAT(g_action.get<Show>(), NotNull());
|
|
|
+}
|
|
|
+
|
|
|
+TEST(ActionTest, CanStoreDefaultAction) {
|
|
|
+ Git git = parse<Git>({"", "remote"});
|
|
|
+
|
|
|
+ program::ArgumentTestHelper::main(git);
|
|
|
+ EXPECT_THAT(g_action.get<Show>(), NotNull());
|
|
|
}
|