1 /////////////////////////////////////////////////////////////////////////////// 2 // 3 // Copyright (c) 2015 Microsoft Corporation. All rights reserved. 4 // 5 // This code is licensed under the MIT License (MIT). 6 // 7 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 8 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 9 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 10 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 12 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 13 // THE SOFTWARE. 14 // 15 /////////////////////////////////////////////////////////////////////////////// 16 17 #ifdef _MSC_VER 18 // blanket turn off warnings from CppCoreCheck from catch 19 // so people aren't annoyed by them when running the tool. 20 #pragma warning(disable : 26440 26426) // from catch 21 22 #endif 23 24 #include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK, TEST_... 25 26 #include <gsl/gsl_assert> // for Expects, fail_fast (ptr only) 27 #include <gsl/pointers> // for owner 28 #include <gsl/span> // for span, dynamic_extent 29 #include <gsl/string_span> // for basic_string_span, operator==, ensure_z 30 31 #include <algorithm> // for move, find 32 #include <cstddef> // for size_t 33 #include <map> // for map 34 #include <string> // for basic_string, string, char_traits, operat... 35 #include <type_traits> // for remove_reference<>::type 36 #include <vector> // for vector, allocator 37 38 using namespace std; 39 using namespace gsl; 40 41 // Generic string functions 42 43 namespace generic 44 { 45 46 template <typename CharT> 47 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 48 GSL_SUPPRESS(f.23) // NO-FORMAT: attribute 49 auto strlen(const CharT* s) 50 { 51 auto p = s; 52 while (*p) ++p; 53 return p - s; 54 } 55 56 template <typename CharT> 57 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 58 auto strnlen(const CharT* s, std::size_t n) 59 { 60 return std::find(s, s + n, CharT{0}) - s; 61 } 62 63 } // namespace generic 64 65 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 66 TEST_CASE("TestLiteralConstruction") 67 { 68 cwstring_span<> v = ensure_z(L"Hello"); 69 CHECK(5 == v.length()); 70 71 #ifdef CONFIRM_COMPILATION_ERRORS 72 wstring_span<> v2 = ensure0(L"Hello"); 73 #endif 74 } 75 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 76 77 TEST_CASE("TestConstructFromStdString") 78 { 79 std::string s = "Hello there world"; 80 cstring_span<> v = s; 81 CHECK(v.length() == static_cast<cstring_span<>::index_type>(s.length())); 82 } 83 84 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 85 TEST_CASE("TestConstructFromStdVector") 86 { 87 std::vector<char> vec(5, 'h'); 88 string_span<> v{vec}; 89 CHECK(v.length() == static_cast<string_span<>::index_type>(vec.size())); 90 } 91 92 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 93 TEST_CASE("TestStackArrayConstruction") 94 { 95 wchar_t stack_string[] = L"Hello"; 96 97 { 98 cwstring_span<> v = ensure_z(stack_string); 99 CHECK(v.length() == 5); 100 } 101 102 { 103 cwstring_span<> v = stack_string; 104 CHECK(v.length() == 5); 105 } 106 107 { 108 wstring_span<> v = ensure_z(stack_string); 109 CHECK(v.length() == 5); 110 } 111 112 { 113 wstring_span<> v = stack_string; 114 CHECK(v.length() == 5); 115 } 116 } 117 118 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 119 TEST_CASE("TestConstructFromConstCharPointer") 120 { 121 const char* s = "Hello"; 122 cstring_span<> v = ensure_z(s); 123 CHECK(v.length() == 5); 124 } 125 126 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 127 TEST_CASE("TestConversionToConst") 128 { 129 char stack_string[] = "Hello"; 130 string_span<> v = ensure_z(stack_string); 131 cstring_span<> v2 = v; 132 CHECK(v.length() == v2.length()); 133 } 134 135 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 136 TEST_CASE("TestConversionFromConst") 137 { 138 char stack_string[] = "Hello"; 139 cstring_span<> v = ensure_z(stack_string); 140 (void) v; 141 #ifdef CONFIRM_COMPILATION_ERRORS 142 string_span<> v2 = v; 143 string_span<> v3 = "Hello"; 144 #endif 145 } 146 147 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 148 TEST_CASE("TestToString") 149 { 150 auto s = gsl::to_string(cstring_span<>{}); 151 CHECK(s.length() == 0); 152 153 char stack_string[] = "Hello"; 154 cstring_span<> v = ensure_z(stack_string); 155 auto s2 = gsl::to_string(v); 156 CHECK(static_cast<cstring_span<>::index_type>(s2.length()) == v.length()); 157 CHECK(s2.length() == 5); 158 } 159 160 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 161 TEST_CASE("TestToBasicString") 162 { 163 auto s = gsl::to_basic_string<char, std::char_traits<char>, ::std::allocator<char>>( 164 cstring_span<>{}); 165 CHECK(s.length() == 0); 166 167 char stack_string[] = "Hello"; 168 cstring_span<> v = ensure_z(stack_string); 169 auto s2 = gsl::to_basic_string<char, std::char_traits<char>, ::std::allocator<char>>(v); 170 CHECK(static_cast<cstring_span<>::index_type>(s2.length()) == v.length()); 171 CHECK(s2.length() == 5); 172 } 173 174 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 175 GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute 176 TEST_CASE("EqualityAndImplicitConstructors") 177 { 178 { 179 cstring_span<> span = "Hello"; 180 cstring_span<> span1; 181 182 // comparison to empty span 183 CHECK(span1 != span); 184 CHECK(span != span1); 185 } 186 187 { 188 cstring_span<> span = "Hello"; 189 cstring_span<> span1 = "Hello1"; 190 191 // comparison to different span 192 CHECK(span1 != span); 193 CHECK(span != span1); 194 } 195 196 { 197 cstring_span<> span = "Hello"; 198 199 const char ar[] = {'H', 'e', 'l', 'l', 'o'}; 200 const char ar1[] = "Hello"; 201 const char ar2[10] = "Hello"; 202 const char* ptr = "Hello"; 203 const std::string str = "Hello"; 204 const std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 205 gsl::span<const char> sp = ensure_z("Hello"); 206 207 // comparison to literal 208 CHECK(span == cstring_span<>("Hello")); 209 210 // comparison to static array with no null termination 211 CHECK(span == cstring_span<>(ar)); 212 213 // comparison to static array with null at the end 214 CHECK(span == cstring_span<>(ar1)); 215 216 // comparison to static array with null in the middle 217 CHECK(span == cstring_span<>(ar2)); 218 219 // comparison to null-terminated c string 220 CHECK(span == cstring_span<>(ptr, 5)); 221 222 // comparison to string 223 CHECK(span == cstring_span<>(str)); 224 225 // comparison to vector of charaters with no null termination 226 CHECK(span == cstring_span<>(vec)); 227 228 // comparison to span 229 CHECK(span == cstring_span<>(sp)); 230 231 // comparison to string_span 232 CHECK(span == span); 233 } 234 235 { 236 char ar[] = {'H', 'e', 'l', 'l', 'o'}; 237 238 string_span<> span = ar; 239 240 char ar1[] = "Hello"; 241 char ar2[10] = "Hello"; 242 char* ptr = ar; 243 std::string str = "Hello"; 244 std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 245 gsl::span<char> sp = ensure_z(ar1); 246 247 // comparison to static array with no null termination 248 CHECK(span == string_span<>(ar)); 249 250 // comparison to static array with null at the end 251 CHECK(span == string_span<>(ar1)); 252 253 // comparison to static array with null in the middle 254 CHECK(span == string_span<>(ar2)); 255 256 // comparison to null-terminated c string 257 CHECK(span == string_span<>(ptr, 5)); 258 259 // comparison to string 260 CHECK(span == string_span<>(str)); 261 262 // comparison to vector of charaters with no null termination 263 CHECK(span == string_span<>(vec)); 264 265 // comparison to span 266 CHECK(span == string_span<>(sp)); 267 268 // comparison to string_span 269 CHECK(span == span); 270 } 271 272 { 273 const char ar[] = {'H', 'e', 'l', 'l', 'o'}; 274 const char ar1[] = "Hello"; 275 const char ar2[10] = "Hello"; 276 const std::string str = "Hello"; 277 const std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 278 const gsl::span<const char> sp = ensure_z("Hello"); 279 280 cstring_span<> span = "Hello"; 281 282 // const span, const other type 283 284 CHECK(span == "Hello"); 285 CHECK(span == ar); 286 CHECK(span == ar1); 287 CHECK(span == ar2); 288 #ifdef CONFIRM_COMPILATION_ERRORS 289 const char* ptr = "Hello"; 290 CHECK(span == ptr); 291 #endif 292 CHECK(span == str); 293 CHECK(span == vec); 294 CHECK(span == sp); 295 296 CHECK("Hello" == span); 297 CHECK(ar == span); 298 CHECK(ar1 == span); 299 CHECK(ar2 == span); 300 #ifdef CONFIRM_COMPILATION_ERRORS 301 CHECK(ptr == span); 302 #endif 303 CHECK(str == span); 304 CHECK(vec == span); 305 CHECK(sp == span); 306 307 // const span, non-const other type 308 309 char _ar[] = {'H', 'e', 'l', 'l', 'o'}; 310 char _ar1[] = "Hello"; 311 char _ar2[10] = "Hello"; 312 char* _ptr = _ar; 313 std::string _str = "Hello"; 314 std::vector<char> _vec = {'H', 'e', 'l', 'l', 'o'}; 315 gsl::span<char> _sp{_ar, 5}; 316 317 CHECK(span == _ar); 318 CHECK(span == _ar1); 319 CHECK(span == _ar2); 320 #ifdef CONFIRM_COMPILATION_ERRORS 321 CHECK(span == _ptr); 322 #endif 323 CHECK(span == _str); 324 CHECK(span == _vec); 325 CHECK(span == _sp); 326 327 CHECK(_ar == span); 328 CHECK(_ar1 == span); 329 CHECK(_ar2 == span); 330 #ifdef CONFIRM_COMPILATION_ERRORS 331 CHECK(_ptr == span); 332 #endif 333 CHECK(_str == span); 334 CHECK(_vec == span); 335 CHECK(_sp == span); 336 337 string_span<> _span{_ptr, 5}; 338 339 // non-const span, non-const other type 340 341 CHECK(_span == _ar); 342 CHECK(_span == _ar1); 343 CHECK(_span == _ar2); 344 #ifdef CONFIRM_COMPILATION_ERRORS 345 CHECK(_span == _ptr); 346 #endif 347 CHECK(_span == _str); 348 CHECK(_span == _vec); 349 CHECK(_span == _sp); 350 351 CHECK(_ar == _span); 352 CHECK(_ar1 == _span); 353 CHECK(_ar2 == _span); 354 #ifdef CONFIRM_COMPILATION_ERRORS 355 CHECK(_ptr == _span); 356 #endif 357 CHECK(_str == _span); 358 CHECK(_vec == _span); 359 CHECK(_sp == _span); 360 361 // non-const span, const other type 362 363 CHECK(_span == "Hello"); 364 CHECK(_span == ar); 365 CHECK(_span == ar1); 366 CHECK(_span == ar2); 367 #ifdef CONFIRM_COMPILATION_ERRORS 368 CHECK(_span == ptr); 369 #endif 370 CHECK(_span == str); 371 CHECK(_span == vec); 372 CHECK(_span == sp); 373 374 CHECK("Hello" == _span); 375 CHECK(ar == _span); 376 CHECK(ar1 == _span); 377 CHECK(ar2 == _span); 378 #ifdef CONFIRM_COMPILATION_ERRORS 379 CHECK(ptr == _span); 380 #endif 381 CHECK(str == _span); 382 CHECK(vec == _span); 383 CHECK(sp == _span); 384 385 // two spans 386 387 CHECK(_span == span); 388 CHECK(span == _span); 389 } 390 391 { 392 std::vector<char> str1 = {'H', 'e', 'l', 'l', 'o'}; 393 cstring_span<> span1 = str1; 394 std::vector<char> str2 = std::move(str1); 395 cstring_span<> span2 = str2; 396 397 // comparison of spans from the same vector before and after move (ok) 398 CHECK(span1 == span2); 399 } 400 } 401 402 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 403 GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute 404 TEST_CASE("ComparisonAndImplicitConstructors") 405 { 406 { 407 cstring_span<> span = "Hello"; 408 409 const char ar[] = {'H', 'e', 'l', 'l', 'o'}; 410 const char ar1[] = "Hello"; 411 const char ar2[10] = "Hello"; 412 const char* ptr = "Hello"; 413 const std::string str = "Hello"; 414 const std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 415 416 // comparison to literal 417 CHECK(span < cstring_span<>("Helloo")); 418 CHECK(span > cstring_span<>("Hell")); 419 420 // comparison to static array with no null termination 421 CHECK(span >= cstring_span<>(ar)); 422 423 // comparison to static array with null at the end 424 CHECK(span <= cstring_span<>(ar1)); 425 426 // comparison to static array with null in the middle 427 CHECK(span >= cstring_span<>(ar2)); 428 429 // comparison to null-terminated c string 430 CHECK(span <= cstring_span<>(ptr, 5)); 431 432 // comparison to string 433 CHECK(span >= cstring_span<>(str)); 434 435 // comparison to vector of charaters with no null termination 436 CHECK(span <= cstring_span<>(vec)); 437 } 438 439 { 440 char ar[] = {'H', 'e', 'l', 'l', 'o'}; 441 442 string_span<> span = ar; 443 444 char larr[] = "Hell"; 445 char rarr[] = "Helloo"; 446 447 char ar1[] = "Hello"; 448 char ar2[10] = "Hello"; 449 char* ptr = ar; 450 std::string str = "Hello"; 451 std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 452 453 // comparison to static array with no null termination 454 CHECK(span <= string_span<>(ar)); 455 CHECK(span < string_span<>(rarr)); 456 CHECK(span > string_span<>(larr)); 457 458 // comparison to static array with null at the end 459 CHECK(span >= string_span<>(ar1)); 460 461 // comparison to static array with null in the middle 462 CHECK(span <= string_span<>(ar2)); 463 464 // comparison to null-terminated c string 465 CHECK(span >= string_span<>(ptr, 5)); 466 467 // comparison to string 468 CHECK(span <= string_span<>(str)); 469 470 // comparison to vector of charaters with no null termination 471 CHECK(span >= string_span<>(vec)); 472 } 473 } 474 475 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 476 GSL_SUPPRESS(r.11) // NO-FORMAT: attribute 477 GSL_SUPPRESS(r.3) // NO-FORMAT: attribute 478 GSL_SUPPRESS(r.5) // NO-FORMAT: attribute 479 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 480 TEST_CASE("ConstrutorsEnsureZ") 481 { 482 // remove z from literals 483 { 484 cstring_span<> sp = "hello"; 485 CHECK((sp.length() == 5)); 486 } 487 488 // take the string as is 489 { 490 auto str = std::string("hello"); 491 cstring_span<> sp = str; 492 CHECK((sp.length() == 5)); 493 } 494 495 // ensure z on c strings 496 { 497 gsl::owner<char*> ptr = new char[3]; 498 499 ptr[0] = 'a'; 500 ptr[1] = 'b'; 501 ptr[2] = '\0'; 502 503 string_span<> span = ensure_z(ptr); 504 CHECK(span.length() == 2); 505 506 delete[] ptr; 507 } 508 } 509 510 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 511 GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute 512 TEST_CASE("Constructors") 513 { 514 // creating cstring_span 515 516 // from span of a final extent 517 { 518 span<const char, 6> sp = "Hello"; 519 cstring_span<> span = sp; 520 CHECK(span.length() == 6); 521 } 522 523 // from const span of a final extent to non-const string_span 524 #ifdef CONFIRM_COMPILATION_ERRORS 525 { 526 span<const char, 6> sp = "Hello"; 527 string_span<> span = sp; 528 CHECK(span.length() == 6); 529 } 530 #endif 531 532 // from string temporary 533 #ifdef CONFIRM_COMPILATION_ERRORS 534 { 535 cstring_span<> span = std::string("Hello"); 536 } 537 #endif 538 539 // default 540 { 541 cstring_span<> span; 542 CHECK(span.length() == 0); 543 } 544 545 // from string literal 546 { 547 cstring_span<> span = "Hello"; 548 CHECK(span.length() == 5); 549 } 550 551 // from const static array 552 { 553 const char ar[] = {'H', 'e', 'l', 'l', 'o'}; 554 cstring_span<> span = ar; 555 CHECK(span.length() == 5); 556 } 557 558 // from non-const static array 559 { 560 char ar[] = {'H', 'e', 'l', 'l', 'o'}; 561 cstring_span<> span = ar; 562 CHECK(span.length() == 5); 563 } 564 565 // from const ptr and length 566 { 567 const char* ptr = "Hello"; 568 cstring_span<> span{ptr, 5}; 569 CHECK(span.length() == 5); 570 } 571 572 // from const ptr and length, include 0 573 { 574 const char* ptr = "Hello"; 575 cstring_span<> span{ptr, 6}; 576 CHECK(span.length() == 6); 577 } 578 579 // from const ptr and length, 0 inside 580 { 581 const char* ptr = "He\0lo"; 582 cstring_span<> span{ptr, 5}; 583 CHECK(span.length() == 5); 584 } 585 586 // from non-const ptr and length 587 { 588 char ar[] = {'H', 'e', 'l', 'l', 'o'}; 589 char* ptr = ar; 590 cstring_span<> span{ptr, 5}; 591 CHECK(span.length() == 5); 592 } 593 594 // from non-const ptr and length, 0 inside 595 { 596 char ar[] = {'H', 'e', '\0', 'l', 'o'}; 597 char* ptr = ar; 598 cstring_span<> span{ptr, 5}; 599 CHECK(span.length() == 5); 600 } 601 602 // from const string 603 { 604 const std::string str = "Hello"; 605 const cstring_span<> span = str; 606 CHECK(span.length() == 5); 607 } 608 609 // from non-const string 610 { 611 std::string str = "Hello"; 612 const cstring_span<> span = str; 613 CHECK(span.length() == 5); 614 } 615 616 // from const vector 617 { 618 const std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 619 const cstring_span<> span = vec; 620 CHECK(span.length() == 5); 621 } 622 623 // from non-const vector 624 { 625 std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 626 const cstring_span<> span = vec; 627 CHECK(span.length() == 5); 628 } 629 630 // from const span 631 { 632 const std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 633 const span<const char> inner = vec; 634 const cstring_span<> span = inner; 635 CHECK(span.length() == 5); 636 } 637 638 // from non-const span 639 { 640 std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 641 const span<char> inner = vec; 642 const cstring_span<> span = inner; 643 CHECK(span.length() == 5); 644 } 645 646 // from const string_span 647 { 648 const std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 649 const cstring_span<> tmp = vec; 650 const cstring_span<> span = tmp; 651 CHECK(span.length() == 5); 652 } 653 654 // from non-const string_span 655 { 656 std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 657 string_span<> tmp = vec; 658 cstring_span<> span = tmp; 659 CHECK(span.length() == 5); 660 } 661 662 // creating string_span 663 664 // from string literal 665 { 666 #ifdef CONFIRM_COMPILATION_ERRORS 667 string_span<> span = "Hello"; 668 #endif 669 } 670 671 // from const static array 672 { 673 #ifdef CONFIRM_COMPILATION_ERRORS 674 const char ar[] = {'H', 'e', 'l', 'l', 'o'}; 675 string_span<> span = ar; 676 CHECK(span.length() == 5); 677 #endif 678 } 679 680 // from non-const static array 681 { 682 char ar[] = {'H', 'e', 'l', 'l', 'o'}; 683 string_span<> span = ar; 684 CHECK(span.length() == 5); 685 } 686 687 // from const ptr and length 688 { 689 #ifdef CONFIRM_COMPILATION_ERRORS 690 const char* ptr = "Hello"; 691 string_span<> span{ptr, 5}; 692 CHECK(span.length() == 5); 693 #endif 694 } 695 696 // from non-const ptr and length 697 { 698 char ar[] = {'H', 'e', 'l', 'l', 'o'}; 699 char* ptr = ar; 700 string_span<> span{ptr, 5}; 701 CHECK(span.length() == 5); 702 } 703 704 // from const string 705 { 706 #ifdef CONFIRM_COMPILATION_ERRORS 707 const std::string str = "Hello"; 708 string_span<> span = str; 709 CHECK(span.length() == 5); 710 #endif 711 } 712 713 // from non-const string 714 { 715 std::string str = "Hello"; 716 string_span<> span = str; 717 CHECK(span.length() == 5); 718 } 719 720 // from const vector 721 { 722 #ifdef CONFIRM_COMPILATION_ERRORS 723 const std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 724 string_span<> span = vec; 725 CHECK(span.length() == 5); 726 #endif 727 } 728 729 // from non-const vector 730 { 731 std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 732 string_span<> span = vec; 733 CHECK(span.length() == 5); 734 } 735 736 // from const span 737 { 738 #ifdef CONFIRM_COMPILATION_ERRORS 739 std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 740 const span<const char> inner = vec; 741 string_span<> span = inner; 742 CHECK(span.length() == 5); 743 #endif 744 } 745 746 // from non-const span 747 { 748 std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 749 span<char> inner = vec; 750 string_span<> span = inner; 751 CHECK(span.length() == 5); 752 } 753 754 // from non-const span of non-const data from const vector 755 { 756 #ifdef CONFIRM_COMPILATION_ERRORS 757 const std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 758 const span<char> inner = vec; 759 string_span<> span = inner; 760 CHECK(span.length() == 5); 761 #endif 762 } 763 764 // from const string_span 765 { 766 #ifdef CONFIRM_COMPILATION_ERRORS 767 std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 768 cstring_span<> tmp = vec; 769 string_span<> span = tmp; 770 CHECK(span.length() == 5); 771 #endif 772 } 773 774 // from non-const string_span 775 { 776 std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 777 const string_span<> tmp = vec; 778 const string_span<> span = tmp; 779 CHECK(span.length() == 5); 780 } 781 782 // from non-const string_span from const vector 783 { 784 #ifdef CONFIRM_COMPILATION_ERRORS 785 const std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 786 string_span<> tmp = vec; 787 string_span<> span = tmp; 788 CHECK(span.length() == 5); 789 #endif 790 } 791 792 // from const string_span of non-const data 793 { 794 std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 795 const string_span<> tmp = vec; 796 const string_span<> span = tmp; 797 CHECK(span.length() == 5); 798 } 799 } 800 801 template <typename T> 802 T move_wrapper(T&& t) 803 { 804 return std::move(t); 805 } 806 807 template <class T> 808 T create() 809 { 810 return T{}; 811 } 812 813 template <class T> 814 void use(basic_string_span<T, gsl::dynamic_extent>) 815 { 816 } 817 818 TEST_CASE("MoveConstructors") 819 { 820 // move string_span 821 { 822 cstring_span<> span = "Hello"; 823 const auto span1 = std::move(span); 824 CHECK(span1.length() == 5); 825 } 826 { 827 cstring_span<> span = "Hello"; 828 const auto span1 = move_wrapper(std::move(span)); 829 CHECK(span1.length() == 5); 830 } 831 { 832 cstring_span<> span = "Hello"; 833 const auto span1 = move_wrapper(std::move(span)); 834 CHECK(span1.length() == 5); 835 } 836 837 // move span 838 { 839 span<const char> span = ensure_z("Hello"); 840 const cstring_span<> span1 = std::move(span); 841 CHECK(span1.length() == 5); 842 } 843 { 844 span<const char> span = ensure_z("Hello"); 845 const cstring_span<> span2 = move_wrapper(std::move(span)); 846 CHECK(span2.length() == 5); 847 } 848 849 // move string 850 { 851 #ifdef CONFIRM_COMPILATION_ERRORS 852 std::string str = "Hello"; 853 string_span<> span = std::move(str); 854 CHECK(span.length() == 5); 855 #endif 856 } 857 { 858 #ifdef CONFIRM_COMPILATION_ERRORS 859 std::string str = "Hello"; 860 string_span<> span = move_wrapper<std::string>(std::move(str)); 861 CHECK(span.length() == 5); 862 #endif 863 } 864 { 865 #ifdef CONFIRM_COMPILATION_ERRORS 866 use<char>(create<string>()); 867 #endif 868 } 869 870 // move container 871 { 872 #ifdef CONFIRM_COMPILATION_ERRORS 873 std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 874 string_span<> span = std::move(vec); 875 CHECK(span.length() == 5); 876 #endif 877 } 878 { 879 #ifdef CONFIRM_COMPILATION_ERRORS 880 std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; 881 string_span<> span = move_wrapper<std::vector<char>>(std::move(vec)); 882 CHECK(span.length() == 5); 883 #endif 884 } 885 { 886 #ifdef CONFIRM_COMPILATION_ERRORS 887 use<char>(create<std::vector<char>>()); 888 #endif 889 } 890 } 891 892 TEST_CASE("Conversion") 893 { 894 #ifdef CONFIRM_COMPILATION_ERRORS 895 cstring_span<> span = "Hello"; 896 cwstring_span<> wspan{span}; 897 CHECK(wspan.length() == 5); 898 #endif 899 } 900 901 czstring_span<> CreateTempName(string_span<> span) 902 { 903 Expects(span.size() > 1); 904 905 int last = 0; 906 if (span.size() > 4) { 907 span[0] = 't'; 908 span[1] = 'm'; 909 span[2] = 'p'; 910 last = 3; 911 } 912 span[last] = '\0'; 913 914 auto ret = span.subspan(0, 4); 915 return {ret}; 916 } 917 918 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 919 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 920 TEST_CASE("zstring") 921 { 922 923 // create zspan from zero terminated string 924 { 925 char buf[1]; 926 buf[0] = '\0'; 927 928 zstring_span<> zspan({buf, 1}); 929 930 CHECK(generic::strlen(zspan.assume_z()) == 0); 931 CHECK(zspan.as_string_span().size() == 0); 932 CHECK(zspan.ensure_z().size() == 0); 933 } 934 935 // create zspan from non-zero terminated string 936 { 937 char buf[1]; 938 buf[0] = 'a'; 939 940 auto workaround_macro = [&]() { const zstring_span<> zspan({buf, 1}); }; 941 CHECK_THROWS_AS(workaround_macro(), fail_fast); 942 } 943 944 // usage scenario: create zero-terminated temp file name and pass to a legacy API 945 { 946 char buf[10]; 947 948 auto name = CreateTempName({buf, 10}); 949 if (!name.empty()) { 950 czstring<> str = name.assume_z(); 951 CHECK(generic::strlen(str) == 3); 952 CHECK(*(str + 3) == '\0'); 953 } 954 } 955 } 956 957 cwzstring_span<> CreateTempNameW(wstring_span<> span) 958 { 959 Expects(span.size() > 1); 960 961 int last = 0; 962 if (span.size() > 4) { 963 span[0] = L't'; 964 span[1] = L'm'; 965 span[2] = L'p'; 966 last = 3; 967 } 968 span[last] = L'\0'; 969 970 auto ret = span.subspan(0, 4); 971 return {ret}; 972 } 973 974 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 975 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 976 TEST_CASE("wzstring") 977 { 978 979 // create zspan from zero terminated string 980 { 981 wchar_t buf[1]; 982 buf[0] = L'\0'; 983 984 wzstring_span<> zspan({buf, 1}); 985 986 CHECK(generic::strnlen(zspan.assume_z(), 1) == 0); 987 CHECK(zspan.as_string_span().size() == 0); 988 CHECK(zspan.ensure_z().size() == 0); 989 } 990 991 // create zspan from non-zero terminated string 992 { 993 wchar_t buf[1]; 994 buf[0] = L'a'; 995 996 const auto workaround_macro = [&]() { const wzstring_span<> zspan({buf, 1}); }; 997 CHECK_THROWS_AS(workaround_macro(), fail_fast); 998 } 999 1000 // usage scenario: create zero-terminated temp file name and pass to a legacy API 1001 { 1002 wchar_t buf[10]; 1003 1004 const auto name = CreateTempNameW({buf, 10}); 1005 if (!name.empty()) { 1006 cwzstring<> str = name.assume_z(); 1007 CHECK(generic::strnlen(str, 10) == 3); 1008 CHECK(*(str + 3) == L'\0'); 1009 } 1010 } 1011 } 1012 1013 cu16zstring_span<> CreateTempNameU16(u16string_span<> span) 1014 { 1015 Expects(span.size() > 1); 1016 1017 int last = 0; 1018 if (span.size() > 4) { 1019 span[0] = u't'; 1020 span[1] = u'm'; 1021 span[2] = u'p'; 1022 last = 3; 1023 } 1024 span[last] = u'\0'; 1025 1026 auto ret = span.subspan(0, 4); 1027 return {ret}; 1028 } 1029 1030 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 1031 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 1032 TEST_CASE("u16zstring") 1033 { 1034 1035 // create zspan from zero terminated string 1036 { 1037 char16_t buf[1]; 1038 buf[0] = L'\0'; 1039 1040 u16zstring_span<> zspan({buf, 1}); 1041 1042 CHECK(generic::strnlen(zspan.assume_z(), 1) == 0); 1043 CHECK(zspan.as_string_span().size() == 0); 1044 CHECK(zspan.ensure_z().size() == 0); 1045 } 1046 1047 // create zspan from non-zero terminated string 1048 { 1049 char16_t buf[1]; 1050 buf[0] = u'a'; 1051 1052 const auto workaround_macro = [&]() { const u16zstring_span<> zspan({buf, 1}); }; 1053 CHECK_THROWS_AS(workaround_macro(), fail_fast); 1054 } 1055 1056 // usage scenario: create zero-terminated temp file name and pass to a legacy API 1057 { 1058 char16_t buf[10]; 1059 1060 const auto name = CreateTempNameU16({buf, 10}); 1061 if (!name.empty()) { 1062 cu16zstring<> str = name.assume_z(); 1063 CHECK(generic::strnlen(str, 10) == 3); 1064 CHECK(*(str + 3) == L'\0'); 1065 } 1066 } 1067 } 1068 1069 cu32zstring_span<> CreateTempNameU32(u32string_span<> span) 1070 { 1071 Expects(span.size() > 1); 1072 1073 int last = 0; 1074 if (span.size() > 4) { 1075 span[0] = U't'; 1076 span[1] = U'm'; 1077 span[2] = U'p'; 1078 last = 3; 1079 } 1080 span[last] = U'\0'; 1081 1082 auto ret = span.subspan(0, 4); 1083 return {ret}; 1084 } 1085 1086 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 1087 GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 1088 TEST_CASE("u32zstring") 1089 { 1090 1091 // create zspan from zero terminated string 1092 { 1093 char32_t buf[1]; 1094 buf[0] = L'\0'; 1095 1096 u32zstring_span<> zspan({buf, 1}); 1097 1098 CHECK(generic::strnlen(zspan.assume_z(), 1) == 0); 1099 CHECK(zspan.as_string_span().size() == 0); 1100 CHECK(zspan.ensure_z().size() == 0); 1101 } 1102 1103 // create zspan from non-zero terminated string 1104 { 1105 char32_t buf[1]; 1106 buf[0] = u'a'; 1107 1108 const auto workaround_macro = [&]() { const u32zstring_span<> zspan({buf, 1}); }; 1109 CHECK_THROWS_AS(workaround_macro(), fail_fast); 1110 } 1111 1112 // usage scenario: create zero-terminated temp file name and pass to a legacy API 1113 { 1114 char32_t buf[10]; 1115 1116 const auto name = CreateTempNameU32({buf, 10}); 1117 if (!name.empty()) { 1118 cu32zstring<> str = name.assume_z(); 1119 CHECK(generic::strnlen(str, 10) == 3); 1120 CHECK(*(str + 3) == L'\0'); 1121 } 1122 } 1123 } 1124 1125 TEST_CASE("Issue305") 1126 { 1127 std::map<gsl::cstring_span<>, int> foo = {{"foo", 0}, {"bar", 1}}; 1128 CHECK(foo["foo"] == 0); 1129 CHECK(foo["bar"] == 1); 1130 } 1131 1132 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 1133 GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute 1134 TEST_CASE("char16_t type") 1135 { 1136 gsl::cu16string_span<> ss1 = gsl::ensure_z(u"abc"); 1137 CHECK(ss1.size() == 3); 1138 CHECK(ss1.size_bytes() == 6); 1139 1140 std::u16string s1 = gsl::to_string(ss1); 1141 CHECK(s1 == u"abc"); 1142 1143 std::u16string s2 = u"abc"; 1144 gsl::u16string_span<> ss2 = s2; 1145 CHECK(ss2.size() == 3); 1146 1147 gsl::u16string_span<> ss3 = ss2.subspan(1, 1); 1148 CHECK(ss3.size() == 1); 1149 CHECK(ss3[0] == u'b'); 1150 1151 char16_t buf[4]{u'a', u'b', u'c', u'\0'}; 1152 gsl::u16string_span<> ss4{buf, 4}; 1153 CHECK(ss4[3] == u'\0'); 1154 1155 gsl::cu16zstring_span<> ss5(u"abc"); 1156 CHECK(ss5.as_string_span().size() == 3); 1157 1158 gsl::cu16string_span<> ss6 = ss5.as_string_span(); 1159 CHECK(ss6 == ss1); 1160 1161 std::vector<char16_t> v7 = {u'a', u'b', u'c'}; 1162 gsl::cu16string_span<> ss7{v7}; 1163 CHECK(ss7 == ss1); 1164 1165 gsl::cu16string_span<> ss8 = gsl::ensure_z(u"abc"); 1166 gsl::cu16string_span<> ss9 = gsl::ensure_z(u"abc"); 1167 CHECK(ss8 == ss9); 1168 1169 ss9 = gsl::ensure_z(u"abd"); 1170 CHECK(ss8 < ss9); 1171 CHECK(ss8 <= ss9); 1172 CHECK(ss8 != ss9); 1173 } 1174 1175 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 1176 GSL_SUPPRESS(bounds.3) // NO-FORMAT: attribute 1177 TEST_CASE("char32_t type") 1178 { 1179 gsl::cu32string_span<> ss1 = gsl::ensure_z(U"abc"); 1180 CHECK(ss1.size() == 3); 1181 CHECK(ss1.size_bytes() == 12); 1182 1183 std::u32string s1 = gsl::to_string(ss1); 1184 CHECK(s1 == U"abc"); 1185 1186 std::u32string s2 = U"abc"; 1187 gsl::u32string_span<> ss2 = s2; 1188 CHECK(ss2.size() == 3); 1189 1190 gsl::u32string_span<> ss3 = ss2.subspan(1, 1); 1191 CHECK(ss3.size() == 1); 1192 CHECK(ss3[0] == U'b'); 1193 1194 char32_t buf[4]{U'a', U'b', U'c', U'\0'}; 1195 gsl::u32string_span<> ss4{buf, 4}; 1196 CHECK(ss4[3] == u'\0'); 1197 1198 gsl::cu32zstring_span<> ss5(U"abc"); 1199 CHECK(ss5.as_string_span().size() == 3); 1200 1201 gsl::cu32string_span<> ss6 = ss5.as_string_span(); 1202 CHECK(ss6 == ss1); 1203 1204 gsl::cu32string_span<> ss8 = gsl::ensure_z(U"abc"); 1205 gsl::cu32string_span<> ss9 = gsl::ensure_z(U"abc"); 1206 CHECK(ss8 == ss9); 1207 1208 ss9 = gsl::ensure_z(U"abd"); 1209 CHECK(ss8 < ss9); 1210 CHECK(ss8 <= ss9); 1211 CHECK(ss8 != ss9); 1212 } 1213 1214 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 1215 TEST_CASE("as_bytes") 1216 { 1217 cwzstring_span<> v(L"qwerty"); 1218 const auto s = v.as_string_span(); 1219 const auto bs = as_bytes(s); 1220 CHECK(static_cast<const void*>(bs.data()) == static_cast<const void*>(s.data())); 1221 CHECK(bs.size() == s.size_bytes()); 1222 } 1223 1224 GSL_SUPPRESS(con.4) // NO-FORMAT: attribute 1225 TEST_CASE("as_writeable_bytes") 1226 { 1227 wchar_t buf[]{L"qwerty"}; 1228 wzstring_span<> v(buf); 1229 const auto s = v.as_string_span(); 1230 const auto bs = as_writeable_bytes(s); 1231 CHECK(static_cast<const void*>(bs.data()) == static_cast<const void*>(s.data())); 1232 CHECK(bs.size() == s.size_bytes()); 1233 } 1234