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