Line data Source code
1 : // Copyright (c) 2006-2025 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/advgetopt
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 : // advgetopt
21 : //
22 : #include <advgetopt/variables.h>
23 :
24 : #include <advgetopt/exception.h>
25 :
26 :
27 : // self
28 : //
29 : #include "catch_main.h"
30 :
31 :
32 : // C++
33 : //
34 : #include <fstream>
35 : #include <iomanip>
36 :
37 :
38 : // last include
39 : //
40 : #include <snapdev/poison.h>
41 :
42 :
43 :
44 1 : CATCH_TEST_CASE("variables", "[variables][valid]")
45 : {
46 1 : CATCH_START_SECTION("variables: check the variables class")
47 : {
48 1 : advgetopt::variables vars;
49 :
50 : // not set yet
51 3 : CATCH_REQUIRE(vars.get_variable("first-variable") == std::string());
52 1 : CATCH_REQUIRE(vars.get_variables().empty());
53 :
54 3 : CATCH_REQUIRE_FALSE(vars.has_variable("first_variable"));
55 5 : vars.set_variable("first_variable", "it works");
56 1 : CATCH_REQUIRE(vars.get_variables().size() == 1);
57 3 : CATCH_REQUIRE(vars.has_variable("first_variable"));
58 3 : CATCH_REQUIRE(vars.has_variable("first-variable"));
59 3 : CATCH_REQUIRE(vars.get_variable("first_variable") == "it works");
60 3 : CATCH_REQUIRE(vars.get_variable("first-variable") == "it works");
61 :
62 3 : CATCH_REQUIRE_FALSE(vars.has_variable("second::variable"));
63 5 : vars.set_variable("second::variable", "double colon");
64 1 : CATCH_REQUIRE(vars.get_variables().size() == 2);
65 3 : CATCH_REQUIRE(vars.has_variable("second.variable"));
66 3 : CATCH_REQUIRE(vars.has_variable("second..variable"));
67 3 : CATCH_REQUIRE(vars.has_variable("second...variable"));
68 3 : CATCH_REQUIRE(vars.has_variable("second....variable"));
69 3 : CATCH_REQUIRE(vars.has_variable("second:variable"));
70 3 : CATCH_REQUIRE(vars.has_variable("second::variable"));
71 3 : CATCH_REQUIRE(vars.has_variable("second:::variable"));
72 3 : CATCH_REQUIRE(vars.has_variable("second::::variable"));
73 3 : CATCH_REQUIRE(vars.get_variable("second.variable") == "double colon");
74 3 : CATCH_REQUIRE(vars.get_variable("second..variable") == "double colon");
75 3 : CATCH_REQUIRE(vars.get_variable("second...variable") == "double colon");
76 3 : CATCH_REQUIRE(vars.get_variable("second....variable") == "double colon");
77 3 : CATCH_REQUIRE(vars.get_variable("second:variable") == "double colon");
78 3 : CATCH_REQUIRE(vars.get_variable("second::variable") == "double colon");
79 3 : CATCH_REQUIRE(vars.get_variable("second:::variable") == "double colon");
80 3 : CATCH_REQUIRE(vars.get_variable("second::::variable") == "double colon");
81 :
82 3 : CATCH_REQUIRE_FALSE(vars.has_variable("third::::variable"));
83 5 : vars.set_variable("third::::variable", "scope operator");
84 1 : CATCH_REQUIRE(vars.get_variables().size() == 3);
85 3 : CATCH_REQUIRE(vars.has_variable("third::variable"));
86 3 : CATCH_REQUIRE(vars.get_variable("third::variable") == "scope operator");
87 :
88 : // change value
89 5 : vars.set_variable("first_variable", "replaced value");
90 3 : CATCH_REQUIRE(vars.get_variable("first_variable") == "replaced value");
91 1 : CATCH_REQUIRE(vars.get_variables().size() == 3);
92 :
93 : // attempt changing value when already set
94 5 : vars.set_variable("first_variable", "ignored value", advgetopt::assignment_t::ASSIGNMENT_OPTIONAL);
95 3 : CATCH_REQUIRE(vars.get_variable("first_variable") == "replaced value");
96 1 : CATCH_REQUIRE(vars.get_variables().size() == 3);
97 :
98 1 : advgetopt::variables::variable_t list(vars.get_variables());
99 4 : for(auto l : list)
100 : {
101 3 : if(l.first == "first-variable")
102 : {
103 1 : CATCH_REQUIRE(l.second == "replaced value");
104 : }
105 2 : else if(l.first == "second::variable")
106 : {
107 1 : CATCH_REQUIRE(l.second == "double colon");
108 : }
109 : else
110 : {
111 : // if not 1st or 2nd, it has to be 3rd
112 : //
113 1 : CATCH_REQUIRE(l.first == "third::variable");
114 1 : CATCH_REQUIRE(l.second == "scope operator");
115 : }
116 3 : }
117 :
118 : // valid
119 : //
120 3 : std::string processed(vars.process_value("First Var = [${first-variable}]"));
121 1 : CATCH_REQUIRE(processed == "First Var = [replaced value]");
122 :
123 : // missing '}'
124 : //
125 3 : processed = vars.process_value("First Var = [${first-variable]");
126 1 : CATCH_REQUIRE(processed == "First Var = [${first-variable]");
127 :
128 5 : vars.set_variable("loopA", "ref ${loopB}", advgetopt::assignment_t::ASSIGNMENT_OPTIONAL);
129 3 : CATCH_REQUIRE(vars.get_variable("loopA") == "ref ${loopB}");
130 1 : CATCH_REQUIRE(vars.get_variables().size() == 4);
131 :
132 5 : vars.set_variable("loopB", "ref ${loopA}", advgetopt::assignment_t::ASSIGNMENT_OPTIONAL);
133 3 : CATCH_REQUIRE(vars.get_variable("loopB") == "ref ${loopA}");
134 1 : CATCH_REQUIRE(vars.get_variables().size() == 5);
135 :
136 3 : processed = vars.process_value("Looping like crazy: ${loopA}");
137 1 : CATCH_REQUIRE(processed == "Looping like crazy: ref ref <variable \"loopA\" loops>");
138 :
139 3 : processed = vars.process_value("Looping like crazy: ${loopB}");
140 1 : CATCH_REQUIRE(processed == "Looping like crazy: ref ref <variable \"loopB\" loops>");
141 :
142 5 : vars.set_variable("cummulative", "start", advgetopt::assignment_t::ASSIGNMENT_NEW);
143 3 : CATCH_REQUIRE(vars.get_variable("cummulative") == "start");
144 1 : CATCH_REQUIRE(vars.get_variables().size() == 6);
145 5 : vars.set_variable("cummulative", "-middle-", advgetopt::assignment_t::ASSIGNMENT_APPEND);
146 3 : CATCH_REQUIRE(vars.get_variable("cummulative") == "start-middle-");
147 1 : CATCH_REQUIRE(vars.get_variables().size() == 6);
148 5 : vars.set_variable("cummulative", "end", advgetopt::assignment_t::ASSIGNMENT_APPEND);
149 3 : CATCH_REQUIRE(vars.get_variable("cummulative") == "start-middle-end");
150 1 : CATCH_REQUIRE(vars.get_variables().size() == 6);
151 :
152 5 : vars.set_variable("additive", "beg", advgetopt::assignment_t::ASSIGNMENT_APPEND);
153 3 : CATCH_REQUIRE(vars.get_variable("additive") == "beg");
154 1 : CATCH_REQUIRE(vars.get_variables().size() == 7);
155 5 : vars.set_variable("additive", ":mid", advgetopt::assignment_t::ASSIGNMENT_APPEND);
156 3 : CATCH_REQUIRE(vars.get_variable("additive") == "beg:mid");
157 1 : CATCH_REQUIRE(vars.get_variables().size() == 7);
158 5 : vars.set_variable("additive", ":end", advgetopt::assignment_t::ASSIGNMENT_APPEND);
159 3 : CATCH_REQUIRE(vars.get_variable("additive") == "beg:mid:end");
160 1 : CATCH_REQUIRE(vars.get_variables().size() == 7);
161 1 : }
162 1 : CATCH_END_SECTION()
163 1 : }
164 :
165 :
166 4 : CATCH_TEST_CASE("invalid_variable_name", "[variables][invalid]")
167 : {
168 4 : CATCH_START_SECTION("invalid_variable_name: parsing an empty section name throws")
169 8 : CATCH_REQUIRE_THROWS_MATCHES(
170 : advgetopt::variables::canonicalize_variable_name(":bad_start")
171 : , advgetopt::getopt_invalid
172 : , Catch::Matchers::ExceptionMessage(
173 : "getopt_exception: found an empty section name in \":bad_start\"."));
174 4 : CATCH_END_SECTION()
175 :
176 4 : CATCH_START_SECTION("invalid_variable_name: parsing first section name that start with a digit fails")
177 8 : CATCH_REQUIRE_THROWS_MATCHES(
178 : advgetopt::variables::canonicalize_variable_name("3::bad_start")
179 : , advgetopt::getopt_invalid
180 : , Catch::Matchers::ExceptionMessage(
181 : "getopt_exception: a variable name or section name in \"3::bad_start\" starts with a digit, which is not allowed."));
182 4 : CATCH_END_SECTION()
183 :
184 4 : CATCH_START_SECTION("invalid_variable_name: parsing second section name that start with a digit fails")
185 8 : CATCH_REQUIRE_THROWS_MATCHES(
186 : advgetopt::variables::canonicalize_variable_name("good::3::bad_section")
187 : , advgetopt::getopt_invalid
188 : , Catch::Matchers::ExceptionMessage(
189 : "getopt_exception: a variable name or section name in \"good::3::bad_section\" starts with a digit, which is not allowed."));
190 4 : CATCH_END_SECTION()
191 :
192 4 : CATCH_START_SECTION("invalid_variable_name: parsing variable name that start with a digit fails")
193 8 : CATCH_REQUIRE_THROWS_MATCHES(
194 : advgetopt::variables::canonicalize_variable_name("good::and_bad::9times")
195 : , advgetopt::getopt_invalid
196 : , Catch::Matchers::ExceptionMessage(
197 : "getopt_exception: a variable name or section name in \"good::and_bad::9times\" starts with a digit, which is not allowed."));
198 4 : CATCH_END_SECTION()
199 4 : }
200 :
201 :
202 1 : CATCH_TEST_CASE("invalid_variable", "[variables][invalid]")
203 : {
204 1 : CATCH_START_SECTION("invalid_variable: NEW assignment fails if variable exists")
205 : {
206 1 : advgetopt::variables vars;
207 :
208 5 : vars.set_variable("unique", "works", advgetopt::assignment_t::ASSIGNMENT_NEW);
209 3 : CATCH_REQUIRE(vars.get_variable("unique") == "works");
210 1 : CATCH_REQUIRE(vars.get_variables().size() == 1);
211 :
212 11 : CATCH_REQUIRE_THROWS_MATCHES(
213 : vars.set_variable("unique", "fail", advgetopt::assignment_t::ASSIGNMENT_NEW)
214 : , advgetopt::getopt_defined_twice
215 : , Catch::Matchers::ExceptionMessage(
216 : "getopt_exception: variable \"unique\" is already defined."));
217 1 : }
218 1 : CATCH_END_SECTION()
219 1 : }
220 :
221 :
222 :
223 : // vim: ts=4 sw=4 et
|