1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2021 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "library.h"
20 #include "settings.h"
21 #include "standards.h"
22 #include "testsuite.h"
23 #include "token.h"
24 #include "tokenize.h"
25 #include "tokenlist.h"
26 
27 #include <tinyxml2.h>
28 #include <map>
29 #include <string>
30 #include <vector>
31 
32 #define ASSERT_EQ(expected, actual)   ASSERT(expected == actual)
33 
34 class TestLibrary : public TestFixture {
35 public:
TestLibrary()36     TestLibrary() : TestFixture("TestLibrary") {}
37 
38 private:
39     Settings settings;
40 
run()41     void run() OVERRIDE {
42         TEST_CASE(isCompliantValidationExpression);
43         TEST_CASE(empty);
44         TEST_CASE(function);
45         TEST_CASE(function_match_scope);
46         TEST_CASE(function_match_args);
47         TEST_CASE(function_match_args_default);
48         TEST_CASE(function_match_var);
49         TEST_CASE(function_arg);
50         TEST_CASE(function_arg_any);
51         TEST_CASE(function_arg_variadic);
52         TEST_CASE(function_arg_direction);
53         TEST_CASE(function_arg_valid);
54         TEST_CASE(function_arg_minsize);
55         TEST_CASE(function_namespace);
56         TEST_CASE(function_method);
57         TEST_CASE(function_baseClassMethod); // calling method in base class
58         TEST_CASE(function_warn);
59         TEST_CASE(memory);
60         TEST_CASE(memory2); // define extra "free" allocation functions
61         TEST_CASE(memory3);
62         TEST_CASE(resource);
63         TEST_CASE(podtype);
64         TEST_CASE(container);
65         TEST_CASE(version);
66         TEST_CASE(loadLibErrors);
67     }
68 
readLibrary(Library & library,const char * xmldata)69     static Library::Error readLibrary(Library& library, const char* xmldata) {
70         tinyxml2::XMLDocument doc;
71         doc.Parse(xmldata);
72         return library.load(doc);
73     }
74 
isCompliantValidationExpression()75     void isCompliantValidationExpression() {
76         ASSERT_EQUALS(true, Library::isCompliantValidationExpression("-1"));
77         ASSERT_EQUALS(true, Library::isCompliantValidationExpression("1"));
78         ASSERT_EQUALS(true, Library::isCompliantValidationExpression("1:"));
79         ASSERT_EQUALS(true, Library::isCompliantValidationExpression(":1"));
80         ASSERT_EQUALS(true, Library::isCompliantValidationExpression("-1,42"));
81         ASSERT_EQUALS(true, Library::isCompliantValidationExpression("-1,-42"));
82         ASSERT_EQUALS(true, Library::isCompliantValidationExpression("-1.0:42.0"));
83         ASSERT_EQUALS(true, Library::isCompliantValidationExpression("1.175494e-38:3.402823e+38"));
84         ASSERT_EQUALS(true, Library::isCompliantValidationExpression("1.175494e-38,3.402823e+38"));
85         ASSERT_EQUALS(true, Library::isCompliantValidationExpression("1.175494e-38:"));
86         ASSERT_EQUALS(true, Library::isCompliantValidationExpression(":1.175494e-38"));
87         ASSERT_EQUALS(true, Library::isCompliantValidationExpression(":42.0"));
88 
89         // Robustness tests
90         ASSERT_EQUALS(false, Library::isCompliantValidationExpression(nullptr));
91         ASSERT_EQUALS(false, Library::isCompliantValidationExpression("x"));
92     }
93 
empty() const94     void empty() const {
95         // Reading an empty library file is considered to be OK
96         const char xmldata[] = "<?xml version=\"1.0\"?>\n<def/>";
97         Library library;
98         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
99         ASSERT(library.functions.empty());
100     }
101 
function() const102     void function() const {
103         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
104                                "<def>\n"
105                                "  <function name=\"foo\">\n"
106                                "    <noreturn>false</noreturn>\n"
107                                "  </function>\n"
108                                "</def>";
109 
110         TokenList tokenList(nullptr);
111         std::istringstream istr("foo();");
112         tokenList.createTokens(istr);
113         tokenList.front()->next()->astOperand1(tokenList.front());
114 
115         Library library;
116         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
117         ASSERT_EQUALS(library.functions.size(), 1U);
118         ASSERT(library.functions.at("foo").argumentChecks.empty());
119         ASSERT(library.isnotnoreturn(tokenList.front()));
120     }
121 
function_match_scope() const122     void function_match_scope() const {
123         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
124                                "<def>\n"
125                                "  <function name=\"foo\">\n"
126                                "    <arg nr=\"1\"/>"
127                                "  </function>\n"
128                                "</def>";
129 
130         Library library;
131         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
132         {
133             TokenList tokenList(nullptr);
134             std::istringstream istr("fred.foo(123);"); // <- wrong scope, not library function
135             tokenList.createTokens(istr);
136 
137             ASSERT(library.isNotLibraryFunction(tokenList.front()->tokAt(2)));
138         }
139         {
140             TokenList tokenList(nullptr);
141             std::istringstream istr("Fred::foo(123);"); // <- wrong scope, not library function
142             tokenList.createTokens(istr);
143 
144             ASSERT(library.isNotLibraryFunction(tokenList.front()->tokAt(2)));
145         }
146     }
147 
function_match_args() const148     void function_match_args() const {
149         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
150                                "<def>\n"
151                                "  <function name=\"foo\">\n"
152                                "    <arg nr=\"1\"/>"
153                                "  </function>\n"
154                                "</def>";
155 
156         TokenList tokenList(nullptr);
157         std::istringstream istr("foo();"); // <- too few arguments, not library function
158         tokenList.createTokens(istr);
159         Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
160         tokenList.createAst();
161 
162         Library library;
163         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
164         ASSERT(library.isNotLibraryFunction(tokenList.front()));
165     }
166 
function_match_args_default() const167     void function_match_args_default() const {
168         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
169                                "<def>\n"
170                                "  <function name=\"foo\">\n"
171                                "    <arg nr=\"1\"/>"
172                                "    <arg nr=\"2\" default=\"0\"/>"
173                                "  </function>\n"
174                                "</def>";
175 
176         Library library;
177         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
178 
179         {
180             TokenList tokenList(nullptr);
181             std::istringstream istr("foo();"); // <- too few arguments, not library function
182             tokenList.createTokens(istr);
183             Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
184             tokenList.createAst();
185 
186             ASSERT(library.isNotLibraryFunction(tokenList.front()));
187         }
188         {
189             TokenList tokenList(nullptr);
190             std::istringstream istr("foo(a);"); // <- library function
191             tokenList.createTokens(istr);
192             Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
193             tokenList.createAst();
194 
195             ASSERT(!library.isNotLibraryFunction(tokenList.front()));
196         }
197         {
198             TokenList tokenList(nullptr);
199             std::istringstream istr("foo(a, b);"); // <- library function
200             tokenList.createTokens(istr);
201             Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
202             tokenList.createAst();
203 
204             ASSERT(!library.isNotLibraryFunction(tokenList.front()));
205         }
206         {
207             TokenList tokenList(nullptr);
208             std::istringstream istr("foo(a, b, c);"); // <- too much arguments, not library function
209             tokenList.createTokens(istr);
210             Token::createMutualLinks(tokenList.front()->next(), tokenList.back()->previous());
211             tokenList.createAst();
212 
213             ASSERT(library.isNotLibraryFunction(tokenList.front()));
214         }
215     }
216 
function_match_var() const217     void function_match_var() const {
218         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
219                                "<def>\n"
220                                "  <function name=\"foo\">\n"
221                                "    <arg nr=\"1\"/>"
222                                "  </function>\n"
223                                "</def>";
224 
225         TokenList tokenList(nullptr);
226         std::istringstream istr("Fred foo(123);"); // <- Variable declaration, not library function
227         tokenList.createTokens(istr);
228         tokenList.front()->next()->astOperand1(tokenList.front());
229         tokenList.front()->next()->varId(1);
230 
231         Library library;
232         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
233         ASSERT(library.isNotLibraryFunction(tokenList.front()->next()));
234     }
235 
function_arg() const236     void function_arg() const {
237         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
238                                "<def>\n"
239                                "  <function name=\"foo\">\n"
240                                "    <arg nr=\"1\"><not-uninit/></arg>\n"
241                                "    <arg nr=\"2\"><not-null/></arg>\n"
242                                "    <arg nr=\"3\"><formatstr/></arg>\n"
243                                "    <arg nr=\"4\"><strz/></arg>\n"
244                                "    <arg nr=\"5\" default=\"0\"><not-bool/></arg>\n"
245                                "  </function>\n"
246                                "</def>";
247 
248         Library library;
249         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
250         ASSERT_EQUALS(0, library.functions["foo"].argumentChecks[1].notuninit);
251         ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[2].notnull);
252         ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[3].formatstr);
253         ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[4].strz);
254         ASSERT_EQUALS(false, library.functions["foo"].argumentChecks[4].optional);
255         ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[5].notbool);
256         ASSERT_EQUALS(true, library.functions["foo"].argumentChecks[5].optional);
257     }
258 
function_arg_any() const259     void function_arg_any() const {
260         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
261                                "<def>\n"
262                                "<function name=\"foo\">\n"
263                                "   <arg nr=\"any\"><not-uninit/></arg>\n"
264                                "</function>\n"
265                                "</def>";
266 
267         Library library;
268         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
269         ASSERT_EQUALS(0, library.functions["foo"].argumentChecks[-1].notuninit);
270     }
271 
function_arg_variadic() const272     void function_arg_variadic() const {
273         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
274                                "<def>\n"
275                                "<function name=\"foo\">\n"
276                                "   <arg nr=\"1\"></arg>\n"
277                                "   <arg nr=\"variadic\"><not-uninit/></arg>\n"
278                                "</function>\n"
279                                "</def>";
280 
281         Library library;
282         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
283         ASSERT_EQUALS(0, library.functions["foo"].argumentChecks[-1].notuninit);
284 
285         TokenList tokenList(nullptr);
286         std::istringstream istr("foo(a,b,c,d,e);");
287         tokenList.createTokens(istr);
288         tokenList.front()->next()->astOperand1(tokenList.front());
289 
290         ASSERT_EQUALS(false, library.isuninitargbad(tokenList.front(), 1));
291         ASSERT_EQUALS(true, library.isuninitargbad(tokenList.front(), 2));
292         ASSERT_EQUALS(true, library.isuninitargbad(tokenList.front(), 3));
293         ASSERT_EQUALS(true, library.isuninitargbad(tokenList.front(), 4));
294     }
295 
function_arg_direction() const296     void function_arg_direction() const {
297         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
298                                "<def>\n"
299                                "<function name=\"foo\">\n"
300                                "   <arg nr=\"1\" direction=\"in\"></arg>\n"
301                                "   <arg nr=\"2\" direction=\"out\"></arg>\n"
302                                "   <arg nr=\"3\" direction=\"inout\"></arg>\n"
303                                "   <arg nr=\"4\"></arg>\n"
304                                "</function>\n"
305                                "</def>";
306 
307         Library library;
308         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
309 
310         TokenList tokenList(nullptr);
311         std::istringstream istr("foo(a,b,c,d);");
312         tokenList.createTokens(istr);
313         tokenList.front()->next()->astOperand1(tokenList.front());
314 
315         ASSERT(Library::ArgumentChecks::Direction::DIR_IN == library.getArgDirection(tokenList.front(), 1));
316         ASSERT(Library::ArgumentChecks::Direction::DIR_OUT == library.getArgDirection(tokenList.front(), 2));
317         ASSERT(Library::ArgumentChecks::Direction::DIR_INOUT == library.getArgDirection(tokenList.front(), 3));
318         ASSERT(Library::ArgumentChecks::Direction::DIR_UNKNOWN == library.getArgDirection(tokenList.front(), 4));
319     }
320 
function_arg_valid() const321     void function_arg_valid() const {
322         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
323                                "<def>\n"
324                                "  <function name=\"foo\">\n"
325                                "    <arg nr=\"1\"><valid>1:</valid></arg>\n"
326                                "    <arg nr=\"2\"><valid>-7:0</valid></arg>\n"
327                                "    <arg nr=\"3\"><valid>1:5,8</valid></arg>\n"
328                                "    <arg nr=\"4\"><valid>-1,5</valid></arg>\n"
329                                "    <arg nr=\"5\"><valid>:1,5</valid></arg>\n"
330                                "    <arg nr=\"6\"><valid>1.5:</valid></arg>\n"
331                                "    <arg nr=\"7\"><valid>-6.7:-5.5,-3.3:-2.7</valid></arg>\n"
332                                "    <arg nr=\"8\"><valid>0.0:</valid></arg>\n"
333                                "    <arg nr=\"9\"><valid>:2.0</valid></arg>\n"
334                                "    <arg nr=\"10\"><valid>0.0</valid></arg>\n"
335                                "  </function>\n"
336                                "</def>";
337 
338         Library library;
339         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
340 
341         TokenList tokenList(nullptr);
342         std::istringstream istr("foo(a,b,c,d,e,f,g,h,i,j);");
343         tokenList.createTokens(istr);
344         tokenList.front()->next()->astOperand1(tokenList.front());
345 
346         // 1-
347         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 1, -10));
348         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 1, -10.0));
349         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 1, 0));
350         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 1, 0.0));
351         ASSERT_EQUALS(true, library.isIntArgValid(tokenList.front(), 1, 1));
352         ASSERT_EQUALS(true, library.isFloatArgValid(tokenList.front(), 1, 1.0));
353         ASSERT_EQUALS(true, library.isIntArgValid(tokenList.front(), 1, 10));
354         ASSERT_EQUALS(true, library.isFloatArgValid(tokenList.front(), 1, 10.0));
355 
356         // -7-0
357         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 2, -10));
358         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 2, -10.0));
359         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 2, -7.5));
360         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 2, -7.1));
361         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 2, -7));
362         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 2, -7.0));
363         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 2, -3));
364         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 2, -3.0));
365         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 2, -3.5));
366         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 2, 0));
367         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 2, 0.0));
368         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 2, 0.5));
369         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 2, 1));
370         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 2, 1.0));
371 
372         // 1-5,8
373         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 3, 0));
374         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 3, 0.0));
375         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 3, 1));
376         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 3, 1.0));
377         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 3, 3));
378         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 3, 3.0));
379         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 3, 5));
380         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 3, 5.0));
381         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 3, 6));
382         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 3, 6.0));
383         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 3, 7));
384         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 3, 7.0));
385         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 3, 8));
386         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 3, 8.0));
387         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 3, 9));
388         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 3, 9.0));
389 
390         // -1,5
391         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 4, -10));
392         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 4, -10.0));
393         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 4, -1));
394         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 4, -1.0));
395         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 4, 5.000001));
396         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 4, 5.5));
397 
398         // :1,5
399         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 5, -10));
400         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 5, -10.0));
401         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 5, 1));
402         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 5, 1.0));
403         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 5, 2));
404         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 5, 2.0));
405 
406         // 1.5:
407         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 6, 0));
408         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 6, 0.0));
409         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 6, 1));
410         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 6, 1.499999));
411         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 6, 1.5));
412         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 6, 2));
413         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 6, 10));
414 
415         // -6.7:-5.5,-3.3:-2.7
416         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 7, -7));
417         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 7, -7.0));
418         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 7, -6.7000001));
419         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 7, -6.7));
420         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 7, -6));
421         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 7, -6.0));
422         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 7, -5.5));
423         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 7, -5.4999999));
424         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 7, -3.3000001));
425         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 7, -3.3));
426         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 7, -3));
427         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 7, -3.0));
428         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 7, -2.7));
429         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 7, -2.6999999));
430         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 7, -2));
431         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 7, -2.0));
432         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 7, 0));
433         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 7, 0.0));
434         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 7, 3));
435         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 7, 3.0));
436         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 7, 6));
437         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 7, 6.0));
438 
439         // 0.0:
440         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 8, -1));
441         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 8, -1.0));
442         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 8, -0.00000001));
443         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 8, 0));
444         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 8, 0.0));
445         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 8, 0.000000001));
446         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 8, 1));
447         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 8, 1.0));
448 
449         // :2.0
450         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 9, -1));
451         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 9, -1.0));
452         ASSERT_EQUALS(true,  library.isIntArgValid(tokenList.front(), 9, 2));
453         ASSERT_EQUALS(true,  library.isFloatArgValid(tokenList.front(), 9, 2.0));
454         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 9, 2.00000001));
455         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 9, 200));
456         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 9, 200.0));
457 
458         // 0.0
459         ASSERT_EQUALS(false, library.isIntArgValid(tokenList.front(), 10, 0));
460         ASSERT_EQUALS(false, library.isFloatArgValid(tokenList.front(), 10, 0.0));
461     }
462 
function_arg_minsize() const463     void function_arg_minsize() const {
464         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
465                                "<def>\n"
466                                "  <function name=\"foo\">\n"
467                                "    <arg nr=\"1\"><minsize type=\"strlen\" arg=\"2\"/></arg>\n"
468                                "    <arg nr=\"2\"><minsize type=\"argvalue\" arg=\"3\"/></arg>\n"
469                                "    <arg nr=\"3\"/>\n"
470                                "    <arg nr=\"4\"><minsize type=\"value\" value=\"500\"/></arg>\n"
471                                "  </function>\n"
472                                "</def>";
473 
474         Library library;
475         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
476 
477         TokenList tokenList(nullptr);
478         std::istringstream istr("foo(a,b,c,d);");
479         tokenList.createTokens(istr);
480         tokenList.front()->next()->astOperand1(tokenList.front());
481 
482         // arg1: type=strlen arg2
483         const std::vector<Library::ArgumentChecks::MinSize> *minsizes = library.argminsizes(tokenList.front(),1);
484         ASSERT_EQUALS(true, minsizes != nullptr);
485         ASSERT_EQUALS(1U, minsizes ? minsizes->size() : 1U);
486         if (minsizes && minsizes->size() == 1U) {
487             const Library::ArgumentChecks::MinSize &m = minsizes->front();
488             ASSERT_EQUALS(true, Library::ArgumentChecks::MinSize::Type::STRLEN == m.type);
489             ASSERT_EQUALS(2, m.arg);
490         }
491 
492         // arg2: type=argvalue arg3
493         minsizes = library.argminsizes(tokenList.front(), 2);
494         ASSERT_EQUALS(true, minsizes != nullptr);
495         ASSERT_EQUALS(1U, minsizes ? minsizes->size() : 1U);
496         if (minsizes && minsizes->size() == 1U) {
497             const Library::ArgumentChecks::MinSize &m = minsizes->front();
498             ASSERT_EQUALS(true, Library::ArgumentChecks::MinSize::Type::ARGVALUE == m.type);
499             ASSERT_EQUALS(3, m.arg);
500         }
501 
502         // arg4: type=value
503         minsizes = library.argminsizes(tokenList.front(), 4);
504         ASSERT_EQUALS(true, minsizes != nullptr);
505         ASSERT_EQUALS(1U, minsizes ? minsizes->size() : 1U);
506         if (minsizes && minsizes->size() == 1U) {
507             const Library::ArgumentChecks::MinSize &m = minsizes->front();
508             ASSERT(Library::ArgumentChecks::MinSize::Type::VALUE == m.type);
509             ASSERT_EQUALS(500, m.value);
510         }
511     }
512 
function_namespace() const513     void function_namespace() const {
514         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
515                                "<def>\n"
516                                "  <function name=\"Foo::foo,bar\">\n"
517                                "    <noreturn>false</noreturn>\n"
518                                "  </function>\n"
519                                "</def>";
520 
521         Library library;
522         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
523         ASSERT_EQUALS(library.functions.size(), 2U);
524         ASSERT(library.functions.at("Foo::foo").argumentChecks.empty());
525         ASSERT(library.functions.at("bar").argumentChecks.empty());
526 
527         {
528             TokenList tokenList(nullptr);
529             std::istringstream istr("Foo::foo();");
530             tokenList.createTokens(istr);
531             ASSERT(library.isnotnoreturn(tokenList.front()->tokAt(2)));
532         }
533 
534         {
535             TokenList tokenList(nullptr);
536             std::istringstream istr("bar();");
537             tokenList.createTokens(istr);
538             ASSERT(library.isnotnoreturn(tokenList.front()));
539         }
540     }
541 
function_method() const542     void function_method() const {
543         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
544                                "<def>\n"
545                                "  <function name=\"CString::Format\">\n"
546                                "    <noreturn>false</noreturn>\n"
547                                "  </function>\n"
548                                "</def>";
549 
550         Library library;
551         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
552         ASSERT_EQUALS(library.functions.size(), 1U);
553 
554         {
555             Tokenizer tokenizer(&settings, nullptr);
556             std::istringstream istr("CString str; str.Format();");
557             tokenizer.tokenize(istr, "test.cpp");
558             ASSERT(library.isnotnoreturn(Token::findsimplematch(tokenizer.tokens(), "Format")));
559         }
560 
561         {
562             Tokenizer tokenizer(&settings, nullptr);
563             std::istringstream istr("HardDrive hd; hd.Format();");
564             tokenizer.tokenize(istr, "test.cpp");
565             ASSERT(!library.isnotnoreturn(Token::findsimplematch(tokenizer.tokens(), "Format")));
566         }
567     }
568 
function_baseClassMethod() const569     void function_baseClassMethod() const {
570         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
571                                "<def>\n"
572                                "  <function name=\"Base::f\">\n"
573                                "    <arg nr=\"1\"><not-null/></arg>\n"
574                                "  </function>\n"
575                                "</def>";
576 
577         Library library;
578         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
579 
580         {
581             Tokenizer tokenizer(&settings, nullptr);
582             std::istringstream istr("struct X : public Base { void dostuff() { f(0); } };");
583             tokenizer.tokenize(istr, "test.cpp");
584             ASSERT(library.isnullargbad(Token::findsimplematch(tokenizer.tokens(), "f"),1));
585         }
586 
587         {
588             Tokenizer tokenizer(&settings, nullptr);
589             std::istringstream istr("struct X : public Base { void dostuff() { f(1,2); } };");
590             tokenizer.tokenize(istr, "test.cpp");
591             ASSERT(!library.isnullargbad(Token::findsimplematch(tokenizer.tokens(), "f"),1));
592         }
593     }
594 
function_warn() const595     void function_warn() const {
596         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
597                                "<def>\n"
598                                "  <function name=\"a\">\n"
599                                "    <warn severity=\"style\" cstd=\"c99\">Message</warn>\n"
600                                "  </function>\n"
601                                "  <function name=\"b\">\n"
602                                "    <warn severity=\"performance\" cppstd=\"c++11\" reason=\"Obsolescent\" alternatives=\"c,d,e\"/>\n"
603                                "  </function>\n"
604                                "</def>";
605 
606         Library library;
607         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
608 
609         TokenList tokenList(nullptr);
610         std::istringstream istr("a(); b();");
611         tokenList.createTokens(istr);
612 
613         const Library::WarnInfo* a = library.getWarnInfo(tokenList.front());
614         const Library::WarnInfo* b = library.getWarnInfo(tokenList.front()->tokAt(4));
615 
616         ASSERT_EQUALS(2, library.functionwarn.size());
617         ASSERT(a && b);
618         if (a && b) {
619             ASSERT_EQUALS("Message", a->message);
620             ASSERT_EQUALS(Severity::style, a->severity);
621             ASSERT_EQUALS(Standards::C99, a->standards.c);
622             ASSERT_EQUALS(Standards::CPP03, a->standards.cpp);
623 
624             ASSERT_EQUALS("Obsolescent function 'b' called. It is recommended to use 'c', 'd' or 'e' instead.", b->message);
625             ASSERT_EQUALS(Severity::performance, b->severity);
626             ASSERT_EQUALS(Standards::C89, b->standards.c);
627             ASSERT_EQUALS(Standards::CPP11, b->standards.cpp);
628         }
629     }
630 
memory() const631     void memory() const {
632         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
633                                "<def>\n"
634                                "  <memory>\n"
635                                "    <alloc>CreateX</alloc>\n"
636                                "    <dealloc>DeleteX</dealloc>\n"
637                                "  </memory>\n"
638                                "</def>";
639 
640         Library library;
641         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
642         ASSERT(library.functions.empty());
643 
644         ASSERT(Library::ismemory(library.getAllocFuncInfo("CreateX")));
645         ASSERT_EQUALS(library.allocId("CreateX"), library.deallocId("DeleteX"));
646         const Library::AllocFunc* af = library.getAllocFuncInfo("CreateX");
647         ASSERT(af && af->arg == -1);
648         const Library::AllocFunc* df = library.getDeallocFuncInfo("DeleteX");
649         ASSERT(df && df->arg == 1);
650     }
memory2() const651     void memory2() const {
652         const char xmldata1[] = "<?xml version=\"1.0\"?>\n"
653                                 "<def>\n"
654                                 "  <memory>\n"
655                                 "    <alloc>malloc</alloc>\n"
656                                 "    <dealloc>free</dealloc>\n"
657                                 "  </memory>\n"
658                                 "</def>";
659         const char xmldata2[] = "<?xml version=\"1.0\"?>\n"
660                                 "<def>\n"
661                                 "  <memory>\n"
662                                 "    <alloc>foo</alloc>\n"
663                                 "    <dealloc>free</dealloc>\n"
664                                 "  </memory>\n"
665                                 "</def>";
666 
667         Library library;
668         library.loadxmldata(xmldata1, sizeof(xmldata1));
669         library.loadxmldata(xmldata2, sizeof(xmldata2));
670 
671         ASSERT_EQUALS(library.deallocId("free"), library.allocId("malloc"));
672         ASSERT_EQUALS(library.deallocId("free"), library.allocId("foo"));
673     }
memory3() const674     void memory3() const {
675         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
676                                "<def>\n"
677                                "  <memory>\n"
678                                "    <alloc arg=\"5\" init=\"false\">CreateX</alloc>\n"
679                                "    <dealloc arg=\"2\">DeleteX</dealloc>\n"
680                                "  </memory>\n"
681                                "</def>";
682 
683         Library library;
684         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
685         ASSERT(library.functions.empty());
686 
687         const Library::AllocFunc* af = library.getAllocFuncInfo("CreateX");
688         ASSERT(af && af->arg == 5 && !af->initData);
689         const Library::AllocFunc* df = library.getDeallocFuncInfo("DeleteX");
690         ASSERT(df && df->arg == 2);
691     }
692 
resource() const693     void resource() const {
694         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
695                                "<def>\n"
696                                "  <resource>\n"
697                                "    <alloc>CreateX</alloc>\n"
698                                "    <dealloc>DeleteX</dealloc>\n"
699                                "  </resource>\n"
700                                "</def>";
701 
702         Library library;
703         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
704         ASSERT(library.functions.empty());
705 
706         ASSERT(Library::isresource(library.allocId("CreateX")));
707         ASSERT_EQUALS(library.allocId("CreateX"), library.deallocId("DeleteX"));
708     }
709 
podtype() const710     void podtype() const {
711         {
712             const char xmldata[] = "<?xml version=\"1.0\"?>\n"
713                                    "<def>\n"
714                                    "  <podtype name=\"s8\" sign=\"s\" size=\"1\"/>\n"
715                                    "  <podtype name=\"u8\" sign=\"u\" size=\"1\"/>\n"
716                                    "  <podtype name=\"u16\" sign=\"u\" size=\"2\"/>\n"
717                                    "  <podtype name=\"s16\" sign=\"s\" size=\"2\"/>\n"
718                                    "</def>";
719             Library library;
720             ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
721             // s8
722             {
723                 const struct Library::PodType * const type = library.podtype("s8");
724                 ASSERT_EQUALS(true, type != nullptr);
725                 if (type) {
726                     ASSERT_EQUALS(1U, type->size);
727                     ASSERT_EQUALS('s', type->sign);
728                 }
729             }
730             // u8
731             {
732                 const struct Library::PodType * const type = library.podtype("u8");
733                 ASSERT_EQUALS(true, type != nullptr);
734                 if (type) {
735                     ASSERT_EQUALS(1U, type->size);
736                     ASSERT_EQUALS('u', type->sign);
737                 }
738             }
739             // u16
740             {
741                 const struct Library::PodType * const type = library.podtype("u16");
742                 ASSERT_EQUALS(true, type != nullptr);
743                 if (type) {
744                     ASSERT_EQUALS(2U, type->size);
745                     ASSERT_EQUALS('u', type->sign);
746                 }
747             }
748             // s16
749             {
750                 const struct Library::PodType * const type = library.podtype("s16");
751                 ASSERT_EQUALS(true, type != nullptr);
752                 if (type) {
753                     ASSERT_EQUALS(2U, type->size);
754                     ASSERT_EQUALS('s', type->sign);
755                 }
756             }
757             // robustness test: provide cfg without PodType
758             {
759                 const struct Library::PodType * const type = library.podtype("nonExistingPodType");
760                 ASSERT_EQUALS(true, type == nullptr);
761             }
762         }
763     }
764 
container() const765     void container() const {
766         const char xmldata[] = "<?xml version=\"1.0\"?>\n"
767                                "<def>\n"
768                                "  <container id=\"A\" startPattern=\"std :: A &lt;\" endPattern=\"&gt; !!::\" itEndPattern=\"&gt; :: iterator\">\n"
769                                "    <type templateParameter=\"1\"/>\n"
770                                "    <size templateParameter=\"4\">\n"
771                                "      <function name=\"resize\" action=\"resize\"/>\n"
772                                "      <function name=\"clear\" action=\"clear\"/>\n"
773                                "      <function name=\"size\" yields=\"size\"/>\n"
774                                "      <function name=\"empty\" yields=\"empty\"/>\n"
775                                "      <function name=\"push_back\" action=\"push\"/>\n"
776                                "      <function name=\"pop_back\" action=\"pop\"/>\n"
777                                "    </size>\n"
778                                "    <access>\n"
779                                "      <function name=\"at\" yields=\"at_index\"/>\n"
780                                "      <function name=\"begin\" yields=\"start-iterator\"/>\n"
781                                "      <function name=\"end\" yields=\"end-iterator\"/>\n"
782                                "      <function name=\"data\" yields=\"buffer\"/>\n"
783                                "      <function name=\"c_str\" yields=\"buffer-nt\"/>\n"
784                                "      <function name=\"front\" yields=\"item\"/>\n"
785                                "      <function name=\"find\" action=\"find\"/>\n"
786                                "    </access>\n"
787                                "  </container>\n"
788                                "  <container id=\"B\" startPattern=\"std :: B &lt;\" inherits=\"A\" opLessAllowed=\"false\">\n"
789                                "    <size templateParameter=\"3\"/>\n" // Inherits all but templateParameter
790                                "  </container>\n"
791                                "  <container id=\"C\">\n"
792                                "    <type string=\"std-like\"/>\n"
793                                "    <access indexOperator=\"array-like\"/>\n"
794                                "  </container>\n"
795                                "</def>";
796 
797         Library library;
798         ASSERT_EQUALS(true, Library::ErrorCode::OK == (readLibrary(library, xmldata)).errorcode);
799 
800         Library::Container& A = library.containers["A"];
801         Library::Container& B = library.containers["B"];
802         Library::Container& C = library.containers["C"];
803 
804         ASSERT_EQUALS(A.type_templateArgNo, 1);
805         ASSERT_EQUALS(A.size_templateArgNo, 4);
806         ASSERT_EQUALS(A.startPattern, "std :: A <");
807         ASSERT_EQUALS(A.endPattern, "> !!::");
808         ASSERT_EQUALS(A.itEndPattern, "> :: iterator");
809         ASSERT_EQUALS(A.stdStringLike, false);
810         ASSERT_EQUALS(A.arrayLike_indexOp, false);
811         ASSERT_EQUALS(A.opLessAllowed, true);
812         ASSERT_EQ(Library::Container::Yield::SIZE, A.getYield("size"));
813         ASSERT_EQ(Library::Container::Yield::EMPTY, A.getYield("empty"));
814         ASSERT_EQ(Library::Container::Yield::AT_INDEX, A.getYield("at"));
815         ASSERT_EQ(Library::Container::Yield::START_ITERATOR, A.getYield("begin"));
816         ASSERT_EQ(Library::Container::Yield::END_ITERATOR, A.getYield("end"));
817         ASSERT_EQ(Library::Container::Yield::BUFFER, A.getYield("data"));
818         ASSERT_EQ(Library::Container::Yield::BUFFER_NT, A.getYield("c_str"));
819         ASSERT_EQ(Library::Container::Yield::ITEM, A.getYield("front"));
820         ASSERT_EQ(Library::Container::Yield::NO_YIELD, A.getYield("foo"));
821         ASSERT_EQ(Library::Container::Action::RESIZE, A.getAction("resize"));
822         ASSERT_EQ(Library::Container::Action::CLEAR, A.getAction("clear"));
823         ASSERT_EQ(Library::Container::Action::PUSH, A.getAction("push_back"));
824         ASSERT_EQ(Library::Container::Action::POP, A.getAction("pop_back"));
825         ASSERT_EQ(Library::Container::Action::FIND, A.getAction("find"));
826         ASSERT_EQ(Library::Container::Action::NO_ACTION, A.getAction("foo"));
827 
828         ASSERT_EQUALS(B.type_templateArgNo, 1);
829         ASSERT_EQUALS(B.size_templateArgNo, 3);
830         ASSERT_EQUALS(B.startPattern, "std :: B <");
831         ASSERT_EQUALS(B.endPattern, "> !!::");
832         ASSERT_EQUALS(B.itEndPattern, "> :: iterator");
833         ASSERT_EQUALS(B.functions.size(), A.functions.size());
834         ASSERT_EQUALS(B.opLessAllowed, false);
835 
836         ASSERT(C.functions.empty());
837         ASSERT_EQUALS(C.type_templateArgNo, -1);
838         ASSERT_EQUALS(C.size_templateArgNo, -1);
839         ASSERT_EQUALS(C.stdStringLike, true);
840         ASSERT_EQUALS(C.arrayLike_indexOp, true);
841     }
842 
version() const843     void version() const {
844         {
845             const char xmldata[] = "<?xml version=\"1.0\"?>\n"
846                                    "<def>\n"
847                                    "</def>";
848             Library library;
849             const Library::Error err = readLibrary(library, xmldata);
850             ASSERT_EQUALS(true, err.errorcode == Library::ErrorCode::OK);
851         }
852         {
853             const char xmldata[] = "<?xml version=\"1.0\"?>\n"
854                                    "<def format=\"1\">\n"
855                                    "</def>";
856             Library library;
857             const Library::Error err = readLibrary(library, xmldata);
858             ASSERT_EQUALS(true, err.errorcode == Library::ErrorCode::OK);
859         }
860         {
861             const char xmldata[] = "<?xml version=\"1.0\"?>\n"
862                                    "<def format=\"42\">\n"
863                                    "</def>";
864             Library library;
865             const Library::Error err = readLibrary(library, xmldata);
866             ASSERT_EQUALS(true, err.errorcode == Library::ErrorCode::UNSUPPORTED_FORMAT);
867         }
868     }
869 
loadLibError(const char xmldata[],Library::ErrorCode errorcode,const char * file,unsigned line) const870     void loadLibError(const char xmldata[], Library::ErrorCode errorcode, const char* file, unsigned line) const {
871         Library library;
872         assertEquals(file, line, true, errorcode == readLibrary(library, xmldata).errorcode);
873     }
874 
875 #define LOADLIBERROR(xmldata, errorcode) loadLibError(xmldata, errorcode, __FILE__, __LINE__)
876 #define LOADLIB_ERROR_INVALID_RANGE(valid) LOADLIBERROR("<?xml version=\"1.0\"?>\n" \
877                                                         "<def>\n" \
878                                                         "<function name=\"f\">\n" \
879                                                         "<arg nr=\"1\">\n" \
880                                                         "<valid>" valid  "</valid>\n" \
881                                                         "</arg>\n" \
882                                                         "</function>\n" \
883                                                         "</def>", \
884                                                         Library::ErrorCode::BAD_ATTRIBUTE_VALUE)
885 
loadLibErrors() const886     void loadLibErrors() const {
887 
888         LOADLIBERROR("<?xml version=\"1.0\"?>\n"
889                      "<def>\n"
890                      "   <X name=\"uint8_t,std::uint8_t\" size=\"1\"/>\n"
891                      "</def>",
892                      Library::ErrorCode::UNKNOWN_ELEMENT);
893 
894         // #define without attributes
895         LOADLIBERROR("<?xml version=\"1.0\"?>\n"
896                      "<def>\n"
897                      "  <define />\n" // no attributes provided at all
898                      "</def>",
899                      Library::ErrorCode::MISSING_ATTRIBUTE);
900 
901         // #define with name but without value
902         LOADLIBERROR("<?xml version=\"1.0\"?>\n"
903                      "<def>\n"
904                      "  <define name=\"foo\" />\n" // no value provided
905                      "</def>",
906                      Library::ErrorCode::MISSING_ATTRIBUTE);
907 
908         LOADLIBERROR("<?xml version=\"1.0\"?>\n"
909                      "<def>\n"
910                      "  <define value=\"1\" />\n" // no name provided
911                      "</def>",
912                      Library::ErrorCode::MISSING_ATTRIBUTE);
913 
914         LOADLIBERROR("<?xml version=\"1.0\"?>\n"
915                      "<X>\n"
916                      "</X>",
917                      Library::ErrorCode::UNSUPPORTED_FORMAT);
918 
919         // empty range
920         LOADLIB_ERROR_INVALID_RANGE("");
921 
922         // letter as range
923         LOADLIB_ERROR_INVALID_RANGE("a");
924 
925         // letter and number as range
926         LOADLIB_ERROR_INVALID_RANGE("1a");
927 
928         // digit followed by dash
929         LOADLIB_ERROR_INVALID_RANGE("0:2-1");
930 
931         // single dash
932         LOADLIB_ERROR_INVALID_RANGE("-");
933 
934         // range with multiple colons
935         LOADLIB_ERROR_INVALID_RANGE("1:2:3");
936 
937         // extra dot
938         LOADLIB_ERROR_INVALID_RANGE("1.0.0:10");
939 
940         // consecutive dots
941         LOADLIB_ERROR_INVALID_RANGE("1..0:10");
942 
943         // dot followed by dash
944         LOADLIB_ERROR_INVALID_RANGE("1.-0:10");
945 
946         // dot without preceding number
947         LOADLIB_ERROR_INVALID_RANGE(".5:10");
948 
949         // dash followed by dot
950         LOADLIB_ERROR_INVALID_RANGE("-.5:10");
951 
952         // colon followed by dot without preceding number
953         LOADLIB_ERROR_INVALID_RANGE("0:.5");
954 
955         // colon followed by dash followed by dot
956         LOADLIB_ERROR_INVALID_RANGE("-10:-.5");
957 
958         // dot not followed by number
959         LOADLIB_ERROR_INVALID_RANGE("1:5.");
960 
961         // dot not followed by number
962         LOADLIB_ERROR_INVALID_RANGE("1.:5");
963 
964         // dot followed by comma
965         LOADLIB_ERROR_INVALID_RANGE("1:5.,6:10");
966 
967         // comma followed by dot
968         LOADLIB_ERROR_INVALID_RANGE("-10:0,.5:");
969     }
970 };
971 
972 REGISTER_TEST(TestLibrary)
973