1 // Copyright (c) 2017-2021, University of Cincinnati, developed by Henry Schreiner
2 // under NSF AWARD 1414736 and by the respective contributors.
3 // All rights reserved.
4 //
5 // SPDX-License-Identifier: BSD-3-Clause
6 
7 #ifdef CLI11_SINGLE_FILE
8 #include "CLI11.hpp"
9 #else
10 #include "CLI/CLI.hpp"
11 #endif
12 
13 #include "catch.hpp"
14 #include <fstream>
15 
16 using Catch::Matchers::Contains;
17 
18 class SimpleFormatter : public CLI::FormatterBase {
19   public:
SimpleFormatter()20     SimpleFormatter() : FormatterBase() {}
21 
make_help(const CLI::App *,std::string,CLI::AppFormatMode) const22     std::string make_help(const CLI::App *, std::string, CLI::AppFormatMode) const override {
23         return "This is really simple";
24     }
25 };
26 
27 TEST_CASE("Formatter: Nothing", "[formatter]") {
28     CLI::App app{"My prog"};
29 
30     app.formatter(std::make_shared<SimpleFormatter>());
31 
32     std::string help = app.help();
33 
34     CHECK("This is really simple" == help);
35 }
36 
37 TEST_CASE("Formatter: NothingLambda", "[formatter]") {
38     CLI::App app{"My prog"};
39 
40     app.formatter_fn(
__anon68cefdc00102(const CLI::App *, std::string, CLI::AppFormatMode) 41         [](const CLI::App *, std::string, CLI::AppFormatMode) { return std::string("This is really simple"); });
42 
43     std::string help = app.help();
44 
45     CHECK("This is really simple" == help);
46 }
47 
48 TEST_CASE("Formatter: OptCustomize", "[formatter]") {
49     CLI::App app{"My prog"};
50 
51     auto optfmt = std::make_shared<CLI::Formatter>();
52     optfmt->column_width(25);
53     optfmt->label("REQUIRED", "(MUST HAVE)");
54     app.formatter(optfmt);
55 
56     int v{0};
57     app.add_option("--opt", v, "Something")->required();
58 
59     std::string help = app.help();
60 
61     CHECK_THAT(help, Contains("(MUST HAVE)"));
62     CHECK(help == "My prog\n"
63                   "Usage: [OPTIONS]\n\n"
64                   "Options:\n"
65                   "  -h,--help              Print this help message and exit\n"
66                   "  --opt INT (MUST HAVE)  Something\n\n");
67 }
68 
69 TEST_CASE("Formatter: OptCustomizeSimple", "[formatter]") {
70     CLI::App app{"My prog"};
71 
72     app.get_formatter()->column_width(25);
73     app.get_formatter()->label("REQUIRED", "(MUST HAVE)");
74 
75     int v{0};
76     app.add_option("--opt", v, "Something")->required();
77 
78     std::string help = app.help();
79 
80     CHECK_THAT(help, Contains("(MUST HAVE)"));
81     CHECK(help == "My prog\n"
82                   "Usage: [OPTIONS]\n\n"
83                   "Options:\n"
84                   "  -h,--help              Print this help message and exit\n"
85                   "  --opt INT (MUST HAVE)  Something\n\n");
86 }
87 
88 TEST_CASE("Formatter: OptCustomizeOptionText", "[formatter]") {
89     CLI::App app{"My prog"};
90 
91     app.get_formatter()->column_width(25);
92 
93     int v{0};
94     app.add_option("--opt", v, "Something")->option_text("(ARG)");
95 
96     std::string help = app.help();
97 
98     CHECK_THAT(help, Contains("(ARG)"));
99     CHECK(help == "My prog\n"
100                   "Usage: [OPTIONS]\n\n"
101                   "Options:\n"
102                   "  -h,--help              Print this help message and exit\n"
103                   "  --opt (ARG)            Something\n\n");
104 }
105 
106 TEST_CASE("Formatter: FalseFlagExample", "[formatter]") {
107     CLI::App app{"My prog"};
108 
109     app.get_formatter()->column_width(25);
110     app.get_formatter()->label("REQUIRED", "(MUST HAVE)");
111 
112     int v{0};
113     app.add_flag("--opt,!--no_opt", v, "Something");
114 
115     bool flag{false};
116     app.add_flag("!-O,--opt2,--no_opt2{false}", flag, "Something else");
117 
118     std::string help = app.help();
119 
120     CHECK_THAT(help, Contains("--no_opt{false}"));
121     CHECK_THAT(help, Contains("--no_opt2{false}"));
122     CHECK_THAT(help, Contains("-O{false}"));
123 }
124 
125 TEST_CASE("Formatter: AppCustomize", "[formatter]") {
126     CLI::App app{"My prog"};
127     app.add_subcommand("subcom1", "This");
128 
129     auto appfmt = std::make_shared<CLI::Formatter>();
130     appfmt->column_width(20);
131     appfmt->label("Usage", "Run");
132     app.formatter(appfmt);
133 
134     app.add_subcommand("subcom2", "This");
135 
136     std::string help = app.help();
137     CHECK(help == "My prog\n"
138                   "Run: [OPTIONS] [SUBCOMMAND]\n\n"
139                   "Options:\n"
140                   "  -h,--help         Print this help message and exit\n\n"
141                   "Subcommands:\n"
142                   "  subcom1           This\n"
143                   "  subcom2           This\n\n");
144 }
145 
146 TEST_CASE("Formatter: AppCustomizeSimple", "[formatter]") {
147     CLI::App app{"My prog"};
148     app.add_subcommand("subcom1", "This");
149 
150     app.get_formatter()->column_width(20);
151     app.get_formatter()->label("Usage", "Run");
152 
153     app.add_subcommand("subcom2", "This");
154 
155     std::string help = app.help();
156     CHECK(help == "My prog\n"
157                   "Run: [OPTIONS] [SUBCOMMAND]\n\n"
158                   "Options:\n"
159                   "  -h,--help         Print this help message and exit\n\n"
160                   "Subcommands:\n"
161                   "  subcom1           This\n"
162                   "  subcom2           This\n\n");
163 }
164 
165 TEST_CASE("Formatter: AllSub", "[formatter]") {
166     CLI::App app{"My prog"};
167     CLI::App *sub = app.add_subcommand("subcom", "This");
168     sub->add_flag("--insub", "MyFlag");
169 
170     std::string help = app.help("", CLI::AppFormatMode::All);
171     CHECK_THAT(help, Contains("--insub"));
172     CHECK_THAT(help, Contains("subcom"));
173 }
174 
175 TEST_CASE("Formatter: AllSubRequired", "[formatter]") {
176     CLI::App app{"My prog"};
177     CLI::App *sub = app.add_subcommand("subcom", "This");
178     sub->add_flag("--insub", "MyFlag");
179     sub->required();
180     std::string help = app.help("", CLI::AppFormatMode::All);
181     CHECK_THAT(help, Contains("--insub"));
182     CHECK_THAT(help, Contains("subcom"));
183     CHECK_THAT(help, Contains("REQUIRED"));
184 }
185 
186 TEST_CASE("Formatter: NamelessSub", "[formatter]") {
187     CLI::App app{"My prog"};
188     CLI::App *sub = app.add_subcommand("", "This subcommand");
189     sub->add_flag("--insub", "MyFlag");
190 
191     std::string help = app.help("", CLI::AppFormatMode::Normal);
192     CHECK_THAT(help, Contains("--insub"));
193     CHECK_THAT(help, Contains("This subcommand"));
194 }
195 
196 TEST_CASE("Formatter: NamelessSubInGroup", "[formatter]") {
197     CLI::App app{"My prog"};
198     CLI::App *sub = app.add_subcommand("", "This subcommand");
199     CLI::App *sub2 = app.add_subcommand("sub2", "subcommand2");
200     sub->add_flag("--insub", "MyFlag");
201     int val{0};
202     sub2->add_option("pos", val, "positional");
203     sub->group("group1");
204     sub2->group("group1");
205     std::string help = app.help("", CLI::AppFormatMode::Normal);
206     CHECK_THAT(help, Contains("--insub"));
207     CHECK_THAT(help, Contains("This subcommand"));
208     CHECK_THAT(help, Contains("group1"));
209     CHECK_THAT(help, Contains("sub2"));
210     CHECK(help.find("pos") == std::string::npos);
211 }
212