action_test.cpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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> bool has_main(Impl const & args) const {
  13. return static_cast<bool>(args.main_callback);
  14. }
  15. template <typename Impl> int main(Impl const & args) const {
  16. return args.main_callback(args);
  17. }
  18. };
  19. }
  20. template <typename T, size_t N> static T parse(char const * const (&argv)[N]) {
  21. return T(N, argv);
  22. }
  23. program::detail::Any g_action;
  24. template <typename Args, typename Action>
  25. int typed_main(Args const &, Action const & action) {
  26. g_action = program::detail::Any(&action);
  27. return 0;
  28. }
  29. struct Checkout : program::Arguments<Checkout> {
  30. using Arguments::Arguments;
  31. std::string commitish = argument(0, "commit-ish");
  32. };
  33. struct Commit : program::Arguments<Commit> {
  34. using Arguments::Arguments;
  35. std::string message = option("message", 'm');
  36. };
  37. class Push : public program::Arguments<Push> {
  38. public:
  39. using Arguments::Arguments;
  40. std::string remote = argument(0, "repository") = PROGRAM_DEFER(_remote());
  41. private:
  42. std::string _remote() const;
  43. };
  44. struct Bad1 : program::Arguments<Bad1> {
  45. using Arguments::Arguments;
  46. Commit commit = action("commit");
  47. std::string arg0 = argument(0, "arg0");
  48. };
  49. struct Bad2 : program::Arguments<Bad2> {
  50. using Arguments::Arguments;
  51. std::string arg0 = argument(0, "arg0");
  52. Commit commit = action("commit");
  53. };
  54. class Git : program::Arguments<Git> {
  55. public:
  56. using Arguments::Arguments;
  57. std::string pwd = option('C');
  58. bool verbose = flag("verbose", 'v');
  59. private:
  60. Commit commit = action("commit");
  61. Checkout checkout = action("checkout");
  62. Push push = action("push");
  63. };
  64. std::string Push::_remote() const {
  65. if (Git const * git = Arguments::parent<Git>()) { return git->pwd; }
  66. return "";
  67. }
  68. TEST(ActionTest, CannotMixActionAndArgument) {
  69. EXPECT_THROW(Bad1(), program::ArgumentMixingError);
  70. EXPECT_THROW(Bad2(), program::ArgumentMixingError);
  71. }
  72. TEST(ActionTest, CanRunWithMultipleActions) { EXPECT_NO_THROW(Git()); }
  73. TEST(ActionTest, ActionIsRouted) {
  74. Git git = parse<Git>({"", "-v", "commit", "-m", "this is a message"});
  75. program::ArgumentTestHelper helper;
  76. EXPECT_TRUE(helper.has_main(git));
  77. helper.main(git);
  78. EXPECT_THAT(g_action.get<Commit>(), NotNull());
  79. EXPECT_THAT(g_action.get<Commit>()->message, "this is a message");
  80. }
  81. TEST(ActionTest, CanFetchParentInfo) {
  82. Git git = parse<Git>({"", "-C", "./submodules/X", "push"});
  83. program::ArgumentTestHelper helper;
  84. EXPECT_TRUE(helper.has_main(git));
  85. helper.main(git);
  86. EXPECT_THAT(g_action.get<Push>(), NotNull());
  87. EXPECT_THAT(g_action.get<Push>()->remote, "./submodules/X");
  88. }