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