action_test.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. //
  2. // action_test.cpp
  3. // program_args-test
  4. //
  5. // Created by Sam Jaffe on 2/13/22.
  6. //
  7. #include "program_args/arguments.h"
  8. #include "xcode_gtest_helper.h"
  9. using testing::NotNull;
  10. namespace program {
  11. struct ArgumentTestHelper {
  12. template <typename Impl> static int main(Impl const & args) {
  13. return args.invoke();
  14. }
  15. };
  16. }
  17. template <typename T, size_t N> static T parse(char const * const (&argv)[N]) {
  18. return T(N, argv);
  19. }
  20. program::detail::Any g_action;
  21. template <typename Arg, typename... Args>
  22. int typed_main(Arg const &arg, Args const &...args) {
  23. auto const &last = std::get<sizeof...(Args)>(std::forward_as_tuple(arg, args...));
  24. g_action = program::detail::Any(&last);
  25. return 0;
  26. }
  27. struct Checkout : program::Arguments<Checkout> {
  28. using Arguments::Arguments;
  29. std::string commitish = argument(0, "commit-ish");
  30. };
  31. struct Commit : program::Arguments<Commit> {
  32. using Arguments::Arguments;
  33. std::string message = option("message", 'm');
  34. };
  35. class Push : public program::Arguments<Push> {
  36. public:
  37. using Arguments::Arguments;
  38. std::string remote = argument(0, "repository") = PROGRAM_DEFER(_remote());
  39. private:
  40. std::string _remote() const;
  41. };
  42. struct SetUrl : program::Arguments<SetUrl> {
  43. using Arguments::Arguments;
  44. bool push = flag("push") = false;
  45. std::string name = argument(0, "name");
  46. std::string new_url = argument(1, "newurl");
  47. std::string old_url = argument(2, "oldurl") = "";
  48. };
  49. struct Show : program::Arguments<Show> {
  50. using Arguments::Arguments;
  51. bool use_cached = flag('n') = false;
  52. };
  53. struct Remote : public program::Arguments<Remote> {
  54. PROGRAM_ARGS_INVOKE_WITH_DEFAULT(show, show, set_url);
  55. bool verbose = flag('v') = false;
  56. SetUrl set_url = action("set-url");
  57. Show show = action("show");
  58. };
  59. struct Bad1 : program::Arguments<Bad1> {
  60. using Arguments::Arguments;
  61. Commit commit = action("commit");
  62. std::string arg0 = argument(0, "arg0");
  63. };
  64. struct Bad2 : program::Arguments<Bad2> {
  65. using Arguments::Arguments;
  66. std::string arg0 = argument(0, "arg0");
  67. Commit commit = action("commit");
  68. };
  69. struct Git : program::Arguments<Git> {
  70. PROGRAM_ARGS_INVOKE(commit, checkout, push, remote);
  71. std::string pwd = option('C');
  72. bool verbose = flag("verbose", 'v');
  73. Commit commit = action("commit");
  74. Checkout checkout = action("checkout");
  75. Push push = action("push");
  76. Remote remote = action("remote");
  77. };
  78. struct GitPlug : program::Arguments<GitPlug> {
  79. PROGRAM_ARGS_INVOKE_WITH_DEFAULT(*this, commit, checkout);
  80. Commit commit = action("commit");
  81. Checkout checkout = action("checkout");
  82. };
  83. std::string Push::_remote() const {
  84. if (Git const * git = Arguments::parent<Git>()) { return git->pwd; }
  85. return "";
  86. }
  87. TEST(ActionTest, CannotMixActionAndArgument) {
  88. EXPECT_THROW(Bad1(), program::ArgumentMixingError);
  89. EXPECT_THROW(Bad2(), program::ArgumentMixingError);
  90. }
  91. TEST(ActionTest, CanRunWithMultipleActions) { EXPECT_NO_THROW(Git()); }
  92. TEST(ActionTest, ActionIsRouted) {
  93. Git git = parse<Git>({"", "-v", "commit", "-m", "this is a message"});
  94. EXPECT_THAT(git.commit.message, "this is a message");
  95. }
  96. TEST(ActionTest, CanDiveIntoTypedMain) {
  97. Git git = parse<Git>({"", "-v", "commit", "-m", "this is a message"});
  98. program::ArgumentTestHelper::main(git);
  99. EXPECT_THAT(g_action.get<Commit>(), NotNull());
  100. }
  101. TEST(ActionTest, CanFetchParentInfo) {
  102. Git git = parse<Git>({"", "-C", "./submodules/X", "push"});
  103. EXPECT_THAT(git.push.remote, "./submodules/X");
  104. }
  105. TEST(ActionTest, ReturnsFailureOnNoAction) {
  106. Git git = parse<Git>({""});
  107. EXPECT_THAT(program::ArgumentTestHelper::main(git), 1);
  108. }
  109. TEST(ActionTest, CanRecursivelyPerformActions) {
  110. Git git = parse<Git>({"", "remote", "-v", "show", "-n"});
  111. EXPECT_TRUE(git.remote.verbose);
  112. EXPECT_TRUE(git.remote.show.use_cached);
  113. program::ArgumentTestHelper::main(git);
  114. EXPECT_THAT(g_action.get<Show>(), NotNull());
  115. }
  116. TEST(ActionTest, CanStoreDefaultAction) {
  117. Git git = parse<Git>({"", "remote"});
  118. program::ArgumentTestHelper::main(git);
  119. EXPECT_THAT(g_action.get<Show>(), NotNull());
  120. }
  121. TEST(ActionTest, DefaultActionCanBeSelf) {
  122. GitPlug git = parse<GitPlug>({""});
  123. program::ArgumentTestHelper::main(git);
  124. EXPECT_THAT(g_action.get<GitPlug>(), NotNull());
  125. }