Line data Source code
1 : // Copyright (c) 2019-2025 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/prinbee
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 3 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
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 : // self
20 : //
21 : #include "catch_main.h"
22 :
23 :
24 : // prinbee
25 : //
26 : #include <prinbee/pbql/input.h>
27 :
28 : #include <prinbee/exception.h>
29 :
30 :
31 : // snaplogger
32 : //
33 : #include <snaplogger/message.h>
34 :
35 :
36 : // snapdev
37 : //
38 : //#include <snapdev/hexadecimal_string.h>
39 : //#include <snapdev/math.h>
40 : //#include <snapdev/ostream_int128.h>
41 :
42 :
43 : // C++
44 : //
45 : //#include <bitset>
46 : //#include <fstream>
47 : //#include <iomanip>
48 :
49 :
50 : // C
51 : //
52 : //#include <sys/stat.h>
53 : //#include <sys/types.h>
54 :
55 :
56 : // last include
57 : //
58 : #include <snapdev/poison.h>
59 :
60 :
61 :
62 : namespace
63 : {
64 :
65 :
66 :
67 : char const * g_create_secure_table = "#!/usr/bin/pbql\n"
68 : "CREATE SECURE TABLE users (\n"
69 : " name TEXT,\n"
70 : " password TEXT,\n"
71 : " email TEXT,\n"
72 : " PRIMARY KEY (name),\n"
73 : ") WITH (REPLICATION = 3);\n";
74 :
75 :
76 :
77 : } // no name namespace
78 :
79 :
80 :
81 4 : CATCH_TEST_CASE("input", "[input] [pbql]")
82 : {
83 6 : CATCH_START_SECTION("input: verify a script")
84 : {
85 5 : prinbee::pbql::input in(g_create_secure_table, "./my_script.pbql");
86 :
87 1 : prinbee::pbql::location const & l(in.get_location());
88 1 : CATCH_REQUIRE(l.get_filename() == "./my_script.pbql");
89 1 : CATCH_REQUIRE(l.get_column() == 1);
90 1 : CATCH_REQUIRE(l.get_line() == 1);
91 :
92 1 : int line(1);
93 1 : int column(1);
94 1 : std::size_t const max(strlen(g_create_secure_table));
95 137 : for(std::size_t idx(0); idx < max; ++idx)
96 : {
97 136 : char32_t const c(in.getc());
98 136 : CATCH_REQUIRE(c != libutf8::EOS);
99 136 : CATCH_REQUIRE(c == static_cast<char32_t>(g_create_secure_table[idx]));
100 :
101 136 : if(c == '\n')
102 : {
103 7 : ++line;
104 7 : column = 1;
105 : }
106 : else
107 : {
108 129 : ++column;
109 : }
110 136 : CATCH_REQUIRE(l.get_filename() == "./my_script.pbql");
111 136 : CATCH_REQUIRE(l.get_column() == column);
112 136 : CATCH_REQUIRE(l.get_line() == line);
113 :
114 136 : in.ungetc(c);
115 136 : CATCH_REQUIRE(in.getc() == static_cast<char32_t>(g_create_secure_table[idx]));
116 : }
117 1 : }
118 5 : CATCH_END_SECTION()
119 :
120 6 : CATCH_START_SECTION("input: test 1 & 2 & 3 ungetc()")
121 : {
122 : // one unget
123 : {
124 5 : prinbee::pbql::input in("a<b", "./my_script.pbql");
125 1 : char32_t c(in.getc());
126 1 : CATCH_REQUIRE(c == 'a');
127 1 : c = in.getc();
128 1 : CATCH_REQUIRE(c == '<');
129 1 : c = in.getc();
130 1 : CATCH_REQUIRE(c == 'b');
131 : // it's not '=' or '>'
132 1 : in.ungetc(c);
133 1 : in.ungetc(libutf8::EOS); // no effect
134 1 : c = in.getc();
135 1 : CATCH_REQUIRE(c == 'b');
136 1 : c = in.getc();
137 1 : CATCH_REQUIRE(c == libutf8::EOS);
138 1 : }
139 :
140 : // two ungets
141 : {
142 5 : prinbee::pbql::input in("a.b", "./my_script.pbql");
143 1 : char32_t c(in.getc());
144 1 : CATCH_REQUIRE(c == 'a');
145 1 : c = in.getc();
146 1 : CATCH_REQUIRE(c == '.');
147 1 : in.ungetc(libutf8::EOS); // no effect
148 1 : in.ungetc('>');
149 1 : in.ungetc(libutf8::EOS); // no effect
150 1 : in.ungetc('-');
151 1 : in.ungetc(libutf8::EOS); // no effect
152 1 : c = in.getc();
153 1 : CATCH_REQUIRE(c == '-');
154 1 : c = in.getc();
155 1 : CATCH_REQUIRE(c == '>');
156 1 : c = in.getc();
157 1 : CATCH_REQUIRE(c == 'b');
158 1 : c = in.getc();
159 1 : CATCH_REQUIRE(c == libutf8::EOS);
160 1 : }
161 :
162 : // three ungets
163 : {
164 5 : prinbee::pbql::input in("a~b", "./my_script.pbql");
165 1 : char32_t c(in.getc());
166 1 : CATCH_REQUIRE(c == 'a');
167 1 : c = in.getc();
168 1 : CATCH_REQUIRE(c == '~');
169 1 : in.ungetc('=');
170 1 : in.ungetc(libutf8::EOS); // no effect
171 1 : in.ungetc('~');
172 1 : in.ungetc(libutf8::EOS); // no effect
173 1 : in.ungetc('!');
174 1 : c = in.getc();
175 1 : CATCH_REQUIRE(c == '!');
176 1 : c = in.getc();
177 1 : CATCH_REQUIRE(c == '~');
178 1 : c = in.getc();
179 1 : CATCH_REQUIRE(c == '=');
180 1 : c = in.getc();
181 1 : CATCH_REQUIRE(c == 'b');
182 1 : c = in.getc();
183 1 : CATCH_REQUIRE(c == libutf8::EOS);
184 1 : in.ungetc(libutf8::EOS); // no effect
185 1 : c = in.getc();
186 1 : CATCH_REQUIRE(c == libutf8::EOS);
187 1 : }
188 : }
189 5 : CATCH_END_SECTION()
190 :
191 6 : CATCH_START_SECTION("input: three new lines")
192 : {
193 5 : prinbee::pbql::input in("1\r2\n3\r\n*\n", "./my_script.pbql");
194 :
195 1 : prinbee::pbql::location const & l(in.get_location());
196 1 : CATCH_REQUIRE(l.get_filename() == "./my_script.pbql");
197 1 : CATCH_REQUIRE(l.get_column() == 1);
198 1 : CATCH_REQUIRE(l.get_line() == 1);
199 :
200 : {
201 1 : char32_t const c(in.getc());
202 1 : CATCH_REQUIRE(c == '1');
203 1 : CATCH_REQUIRE(l.get_column() == 2);
204 1 : CATCH_REQUIRE(l.get_line() == 1);
205 : }
206 :
207 : {
208 1 : char32_t const c(in.getc());
209 1 : CATCH_REQUIRE(c == '\n');
210 1 : CATCH_REQUIRE(l.get_column() == 1);
211 1 : CATCH_REQUIRE(l.get_line() == 2);
212 : }
213 :
214 : {
215 1 : char32_t const c(in.getc());
216 1 : CATCH_REQUIRE(c == '2');
217 1 : CATCH_REQUIRE(l.get_column() == 2);
218 1 : CATCH_REQUIRE(l.get_line() == 2);
219 : }
220 :
221 : {
222 1 : char32_t const c(in.getc());
223 1 : CATCH_REQUIRE(c == '\n');
224 1 : CATCH_REQUIRE(l.get_column() == 1);
225 1 : CATCH_REQUIRE(l.get_line() == 3);
226 : }
227 :
228 : {
229 1 : char32_t const c(in.getc());
230 1 : CATCH_REQUIRE(c == '3');
231 1 : CATCH_REQUIRE(l.get_column() == 2);
232 1 : CATCH_REQUIRE(l.get_line() == 3);
233 : }
234 :
235 : {
236 1 : char32_t const c(in.getc());
237 1 : CATCH_REQUIRE(c == '\n');
238 1 : CATCH_REQUIRE(l.get_column() == 1);
239 1 : CATCH_REQUIRE(l.get_line() == 4);
240 : }
241 :
242 : {
243 1 : char32_t const c(in.getc());
244 1 : CATCH_REQUIRE(c == '*');
245 1 : CATCH_REQUIRE(l.get_column() == 2);
246 1 : CATCH_REQUIRE(l.get_line() == 4);
247 : }
248 :
249 : {
250 1 : char32_t const c(in.getc());
251 1 : CATCH_REQUIRE(c == '\n');
252 1 : CATCH_REQUIRE(l.get_column() == 1);
253 1 : CATCH_REQUIRE(l.get_line() == 5);
254 : }
255 :
256 : {
257 1 : char32_t const c(in.getc());
258 1 : CATCH_REQUIRE(c == libutf8::EOS);
259 1 : CATCH_REQUIRE(l.get_column() == 1);
260 1 : CATCH_REQUIRE(l.get_line() == 5);
261 : }
262 1 : }
263 5 : CATCH_END_SECTION()
264 :
265 6 : CATCH_START_SECTION("input: create from file")
266 : {
267 1 : std::string const filename(SNAP_CATCH2_NAMESPACE::g_tmp_dir() + "/create_from_file.pbql");
268 : {
269 1 : std::ofstream out(filename);
270 1 : out << g_create_secure_table;
271 1 : }
272 :
273 1 : prinbee::pbql::input::pointer_t in(prinbee::pbql::create_input(filename));
274 :
275 1 : prinbee::pbql::location const & l(in->get_location());
276 1 : CATCH_REQUIRE(l.get_filename() == filename);
277 1 : CATCH_REQUIRE(l.get_column() == 1);
278 1 : CATCH_REQUIRE(l.get_line() == 1);
279 :
280 1 : int line(1);
281 1 : int column(1);
282 1 : std::size_t const max(strlen(g_create_secure_table));
283 137 : for(std::size_t idx(0); idx < max; ++idx)
284 : {
285 136 : char32_t const c(in->getc());
286 136 : CATCH_REQUIRE(c != libutf8::EOS);
287 136 : CATCH_REQUIRE(c == static_cast<char32_t>(g_create_secure_table[idx]));
288 :
289 136 : if(c == '\n')
290 : {
291 7 : ++line;
292 7 : column = 1;
293 : }
294 : else
295 : {
296 129 : ++column;
297 : }
298 136 : CATCH_REQUIRE(l.get_filename() == filename);
299 136 : CATCH_REQUIRE(l.get_column() == column);
300 136 : CATCH_REQUIRE(l.get_line() == line);
301 : }
302 :
303 : {
304 1 : char32_t const c(in->getc());
305 1 : CATCH_REQUIRE(c == libutf8::EOS);
306 1 : CATCH_REQUIRE(l.get_column() == column);
307 1 : CATCH_REQUIRE(l.get_line() == line);
308 : }
309 1 : }
310 5 : CATCH_END_SECTION()
311 4 : }
312 :
313 :
314 2 : CATCH_TEST_CASE("input_error", "[input] [pbql] [error]")
315 : {
316 4 : CATCH_START_SECTION("input: too many ungetc()")
317 : {
318 5 : prinbee::pbql::input in("#!/usr/bin/pbql -r\n", "./my_script.pbql");
319 1 : CATCH_REQUIRE(in.getc() == '#');
320 :
321 1 : in.ungetc('1');
322 1 : in.ungetc('2');
323 1 : in.ungetc('3');
324 :
325 3 : CATCH_REQUIRE_THROWS_MATCHES(
326 : in.ungetc('*')
327 : , prinbee::out_of_range
328 : , Catch::Matchers::ExceptionMessage(
329 : "out_of_range: ungetc() called too many times."));
330 1 : }
331 3 : CATCH_END_SECTION()
332 :
333 4 : CATCH_START_SECTION("input: file not found")
334 : {
335 8 : CATCH_REQUIRE_THROWS_MATCHES(
336 : prinbee::pbql::create_input("unknown.file")
337 : , prinbee::file_not_found
338 : , Catch::Matchers::ExceptionMessage(
339 : "prinbee_exception: could not read \"unknown.file\"."));
340 : }
341 3 : CATCH_END_SECTION()
342 2 : }
343 :
344 :
345 :
346 : // vim: ts=4 sw=4 et
|