Home | History | Annotate | Download | only in tests
      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