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 <\" endPattern=\"> !!::\" itEndPattern=\"> :: 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 <\" 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