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
strlen(const CharT * s)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
strnlen(const CharT * s,std::size_t n)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>
move_wrapper(T && t)802 T move_wrapper(T&& t)
803 {
804     return std::move(t);
805 }
806 
807 template <class T>
create()808 T create()
809 {
810     return T{};
811 }
812 
813 template <class T>
use(basic_string_span<T,gsl::dynamic_extent>)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 
CreateTempName(string_span<> span)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 
__anon032d65960102() 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 
CreateTempNameW(wstring_span<> span)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 
__anon032d65960202() 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 
CreateTempNameU16(u16string_span<> span)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 
__anon032d65960302() 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 
CreateTempNameU32(u32string_span<> span)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 
__anon032d65960402() 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