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#include <UnitTest++/UnitTest++.h>
18#include <cstdlib>
19#include <gsl/string_span>
20#include <vector>
21#include <map>
22
23using namespace std;
24using namespace gsl;
25
26
27SUITE(string_span_tests)
28{
29
30    TEST(TestLiteralConstruction)
31    {
32        cwstring_span<> v = ensure_z(L"Hello");
33        CHECK(5 == v.length());
34
35#ifdef CONFIRM_COMPILATION_ERRORS
36        wstring_span<> v2 = ensure0(L"Hello");
37#endif
38    }
39
40    TEST(TestConstructFromStdString)
41    {
42        std::string s = "Hello there world";
43        cstring_span<> v = s;
44        CHECK(v.length() == static_cast<cstring_span<>::index_type>(s.length()));
45    }
46
47    TEST(TestConstructFromStdVector)
48    {
49        std::vector<char> vec(5, 'h');
50        string_span<> v {vec};
51        CHECK(v.length() == static_cast<string_span<>::index_type>(vec.size()));
52    }
53
54    TEST(TestStackArrayConstruction)
55    {
56        wchar_t stack_string[] = L"Hello";
57
58        {
59            cwstring_span<> v = ensure_z(stack_string);
60            CHECK(v.length() == 5);
61        }
62
63        {
64            cwstring_span<> v = stack_string;
65            CHECK(v.length() == 5);
66        }
67
68        {
69            wstring_span<> v = ensure_z(stack_string);
70            CHECK(v.length() == 5);
71        }
72
73        {
74            wstring_span<> v = stack_string;
75            CHECK(v.length() == 5);
76        }
77    }
78
79    TEST(TestConstructFromConstCharPointer)
80    {
81        const char* s = "Hello";
82        cstring_span<> v = ensure_z(s);
83        CHECK(v.length() == 5);
84    }
85
86    TEST(TestConversionToConst)
87    {
88        char stack_string[] = "Hello";
89        string_span<> v = ensure_z(stack_string);
90        cstring_span<> v2 = v;
91        CHECK(v.length() == v2.length());
92    }
93
94    TEST(TestConversionFromConst)
95    {
96        char stack_string[] = "Hello";
97        cstring_span<> v = ensure_z(stack_string);
98        (void)v;
99#ifdef CONFIRM_COMPILATION_ERRORS
100        string_span<> v2 = v;
101        string_span<> v3 = "Hello";
102#endif
103    }
104
105    TEST(TestToString)
106    {
107        auto s = gsl::to_string(cstring_span<>{});
108        CHECK(s.length() == 0);
109
110        char stack_string[] = "Hello";
111        cstring_span<> v = ensure_z(stack_string);
112        auto s2 = gsl::to_string(v);
113        CHECK(static_cast<cstring_span<>::index_type>(s2.length()) == v.length());
114        CHECK(s2.length() == 5);
115    }
116
117    TEST(TestToBasicString)
118    {
119        auto s = gsl::to_basic_string<char,std::char_traits<char>,::std::allocator<char>>(cstring_span<>{});
120        CHECK(s.length() == 0);
121
122        char stack_string[] = "Hello";
123        cstring_span<> v = ensure_z(stack_string);
124        auto s2 = gsl::to_basic_string<char,std::char_traits<char>,::std::allocator<char>>(v);
125        CHECK(static_cast<cstring_span<>::index_type>(s2.length()) == v.length());
126        CHECK(s2.length() == 5);
127    }
128
129    TEST(EqualityAndImplicitConstructors)
130    {
131        {
132            cstring_span<> span = "Hello";
133            cstring_span<> span1;
134
135            // comparison to empty span
136            CHECK(span1 != span);
137            CHECK(span != span1);
138        }
139
140        {
141            cstring_span<> span = "Hello";
142            cstring_span<> span1 = "Hello1";
143
144            // comparison to different span
145            CHECK(span1 != span);
146            CHECK(span != span1);
147        }
148
149        {
150            cstring_span<> span = "Hello";
151
152            const char ar[] = { 'H', 'e', 'l', 'l', 'o' };
153            const char ar1[] = "Hello";
154            const char ar2[10] = "Hello";
155            const char* ptr = "Hello";
156            const std::string str = "Hello";
157            const std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
158            gsl::span<const char> sp = ensure_z("Hello");
159
160            // comparison to  literal
161            CHECK(span == cstring_span<>("Hello"));
162
163            // comparison to static array with no null termination
164            CHECK(span == cstring_span<>(ar));
165
166            // comparison to static array with null at the end
167            CHECK(span == cstring_span<>(ar1));
168
169            // comparison to static array with null in the middle
170            CHECK(span == cstring_span<>(ar2));
171
172            // comparison to null-terminated c string
173            CHECK(span == cstring_span<>(ptr, 5));
174
175            // comparison to string
176            CHECK(span == cstring_span<>(str));
177
178            // comparison to vector of charaters with no null termination
179            CHECK(span == cstring_span<>(vec));
180
181            // comparison to span
182            CHECK(span == cstring_span<>(sp));
183
184            // comparison to string_span
185            CHECK(span == span);
186        }
187
188        {
189            char ar[] = { 'H', 'e', 'l', 'l', 'o' };
190
191            string_span<> span = ar;
192
193            char ar1[] = "Hello";
194            char ar2[10] = "Hello";
195            char* ptr = ar;
196            std::string str = "Hello";
197            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
198            gsl::span<char> sp = ensure_z(ar1);
199
200            // comparison to static array with no null termination
201            CHECK(span == string_span<>(ar));
202
203            // comparison to static array with null at the end
204            CHECK(span == string_span<>(ar1));
205
206            // comparison to static array with null in the middle
207            CHECK(span == string_span<>(ar2));
208
209            // comparison to null-terminated c string
210            CHECK(span == string_span<>(ptr, 5));
211
212            // comparison to string
213            CHECK(span == string_span<>(str));
214
215            // comparison to vector of charaters with no null termination
216            CHECK(span == string_span<>(vec));
217
218            // comparison to span
219            CHECK(span == string_span<>(sp));
220
221            // comparison to string_span
222            CHECK(span == span);
223        }
224
225
226        {
227            const char ar[] = { 'H', 'e', 'l', 'l', 'o' };
228            const char ar1[] = "Hello";
229            const char ar2[10] = "Hello";
230            const std::string str = "Hello";
231            const std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
232            gsl::span<const char> sp = ensure_z("Hello");
233
234            cstring_span<> span = "Hello";
235
236            // const span, const other type
237
238            CHECK(span == "Hello");
239            CHECK(span == ar);
240            CHECK(span == ar1);
241            CHECK(span == ar2);
242#ifdef CONFIRM_COMPILATION_ERRORS
243            const char* ptr = "Hello";
244            CHECK(span == ptr);
245#endif
246            CHECK(span == str);
247            CHECK(span == vec);
248            CHECK(span == sp);
249
250            CHECK("Hello" == span);
251            CHECK(ar == span);
252            CHECK(ar1 == span);
253            CHECK(ar2 == span);
254#ifdef CONFIRM_COMPILATION_ERRORS
255            CHECK(ptr == span);
256#endif
257            CHECK(str == span);
258            CHECK(vec == span);
259            CHECK(sp == span);
260
261            // const span, non-const other type
262
263            char _ar[] = { 'H', 'e', 'l', 'l', 'o' };
264            char _ar1[] = "Hello";
265            char _ar2[10] = "Hello";
266            char* _ptr = _ar;
267            std::string _str = "Hello";
268            std::vector<char> _vec = { 'H', 'e', 'l', 'l', 'o' };
269            gsl::span<char> _sp{ _ar, 5 };
270
271            CHECK(span == _ar);
272            CHECK(span == _ar1);
273            CHECK(span == _ar2);
274#ifdef CONFIRM_COMPILATION_ERRORS
275            CHECK(span == _ptr);
276#endif
277            CHECK(span == _str);
278            CHECK(span == _vec);
279            CHECK(span == _sp);
280
281            CHECK(_ar == span);
282            CHECK(_ar1 == span);
283            CHECK(_ar2 == span);
284#ifdef CONFIRM_COMPILATION_ERRORS
285            CHECK(_ptr == span);
286#endif
287            CHECK(_str == span);
288            CHECK(_vec == span);
289            CHECK(_sp == span);
290
291            string_span<> _span{ _ptr, 5 };
292
293            // non-const span, non-const other type
294
295            CHECK(_span == _ar);
296            CHECK(_span == _ar1);
297            CHECK(_span == _ar2);
298#ifdef CONFIRM_COMPILATION_ERRORS
299            CHECK(_span == _ptr);
300#endif
301            CHECK(_span == _str);
302            CHECK(_span == _vec);
303            CHECK(_span == _sp);
304
305            CHECK(_ar == _span);
306            CHECK(_ar1 == _span);
307            CHECK(_ar2 == _span);
308#ifdef CONFIRM_COMPILATION_ERRORS
309            CHECK(_ptr == _span);
310#endif
311            CHECK(_str == _span);
312            CHECK(_vec == _span);
313            CHECK(_sp == _span);
314
315            // non-const span, const other type
316
317            CHECK(_span == "Hello");
318            CHECK(_span == ar);
319            CHECK(_span == ar1);
320            CHECK(_span == ar2);
321#ifdef CONFIRM_COMPILATION_ERRORS
322            CHECK(_span == ptr);
323#endif
324            CHECK(_span == str);
325            CHECK(_span == vec);
326            CHECK(_span == sp);
327
328            CHECK("Hello" == _span);
329            CHECK(ar == _span);
330            CHECK(ar1 == _span);
331            CHECK(ar2 == _span);
332#ifdef CONFIRM_COMPILATION_ERRORS
333            CHECK(ptr == _span);
334#endif
335            CHECK(str == _span);
336            CHECK(vec == _span);
337            CHECK(sp == _span);
338
339            // two spans
340
341            CHECK(_span == span);
342            CHECK(span == _span);
343        }
344
345        {
346            std::vector<char> str1 = { 'H', 'e', 'l', 'l', 'o' };
347            cstring_span<> span1 = str1;
348            std::vector<char> str2 = std::move(str1);
349            cstring_span<> span2 = str2;
350
351            // comparison of spans from the same vector before and after move (ok)
352            CHECK(span1 == span2);
353        }
354    }
355
356    TEST(ComparisonAndImplicitConstructors)
357    {
358        {
359            cstring_span<> span = "Hello";
360
361            const char ar[] = { 'H', 'e', 'l', 'l', 'o' };
362            const char ar1[] = "Hello";
363            const char ar2[10] = "Hello";
364            const char* ptr = "Hello";
365            const std::string str = "Hello";
366            const std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
367
368            // comparison to  literal
369            CHECK(span < cstring_span<>("Helloo"));
370            CHECK(span > cstring_span<>("Hell"));
371
372            // comparison to static array with no null termination
373            CHECK(span >= cstring_span<>(ar));
374
375            // comparison to static array with null at the end
376            CHECK(span <= cstring_span<>(ar1));
377
378            // comparison to static array with null in the middle
379            CHECK(span >= cstring_span<>(ar2));
380
381            // comparison to null-terminated c string
382            CHECK(span <= cstring_span<>(ptr, 5));
383
384            // comparison to string
385            CHECK(span >= cstring_span<>(str));
386
387            // comparison to vector of charaters with no null termination
388            CHECK(span <= cstring_span<>(vec));
389        }
390
391        {
392            char ar[] = { 'H', 'e', 'l', 'l', 'o' };
393
394            string_span<> span = ar;
395
396            char larr[] = "Hell";
397            char rarr[] = "Helloo";
398
399            char ar1[] = "Hello";
400            char ar2[10] = "Hello";
401            char* ptr = ar;
402            std::string str = "Hello";
403            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
404
405
406            // comparison to static array with no null termination
407            CHECK(span <= string_span<>(ar));
408            CHECK(span < string_span<>(rarr));
409            CHECK(span > string_span<>(larr));
410
411            // comparison to static array with null at the end
412            CHECK(span >= string_span<>(ar1));
413
414            // comparison to static array with null in the middle
415            CHECK(span <= string_span<>(ar2));
416
417            // comparison to null-terminated c string
418            CHECK(span >= string_span<>(ptr, 5));
419
420            // comparison to string
421            CHECK(span <= string_span<>(str));
422
423            // comparison to vector of charaters with no null termination
424            CHECK(span >= string_span<>(vec));
425        }
426    }
427    TEST(ConstrutorsEnsureZ)
428    {
429        // remove z from literals
430        {
431            cstring_span<> sp = "hello";
432            CHECK((sp.length() == 5));
433        }
434
435        // take the string as is
436        {
437            auto str = std::string("hello");
438            cstring_span<> sp = str;
439            CHECK((sp.length() == 5));
440        }
441
442        // ensure z on c strings
443        {
444            char* ptr = new char[3];
445
446            ptr[0] = 'a';
447            ptr[1] = 'b';
448            ptr[2] = '\0';
449
450            string_span<> span = ensure_z(ptr);
451            CHECK(span.length() == 2);
452
453            delete[] ptr;
454        }
455    }
456
457    TEST(Constructors)
458    {
459        // creating cstring_span
460
461        // from span of a final extent
462        {
463            span<const char, 6> sp = "Hello";
464            cstring_span<> span = sp;
465            CHECK(span.length() == 6);
466        }
467
468        // from const span of a final extent to non-const string_span
469#ifdef CONFIRM_COMPILATION_ERRORS
470        {
471            span<const char, 6> sp = "Hello";
472            string_span<> span = sp;
473            CHECK(span.length() == 6);
474        }
475#endif
476
477        // from string temporary
478#ifdef CONFIRM_COMPILATION_ERRORS
479        {
480            cstring_span<> span = std::string("Hello");
481        }
482#endif
483
484        // default
485        {
486            cstring_span<> span;
487            CHECK(span.length() == 0);
488        }
489
490        // from nullptr
491        {
492            cstring_span<> span(nullptr);
493            CHECK(span.length() == 0);
494        }
495
496        // from string literal
497        {
498            cstring_span<> span = "Hello";
499            CHECK(span.length() == 5);
500        }
501
502        // from const static array
503        {
504            const char ar[] = { 'H', 'e', 'l', 'l', 'o' };
505            cstring_span<> span = ar;
506            CHECK(span.length() == 5);
507        }
508
509        // from non-const static array
510        {
511            char ar[] = { 'H', 'e', 'l', 'l', 'o' };
512            cstring_span<> span = ar;
513            CHECK(span.length() == 5);
514        }
515
516        // from const ptr and length
517        {
518            const char* ptr = "Hello";
519            cstring_span<> span{ ptr, 5 };
520            CHECK(span.length() == 5);
521        }
522
523        // from const ptr and length, include 0
524        {
525            const char* ptr = "Hello";
526            cstring_span<> span{ ptr, 6 };
527            CHECK(span.length() == 6);
528        }
529
530        // from const ptr and length, 0 inside
531        {
532            const char* ptr = "He\0lo";
533            cstring_span<> span{ ptr, 5 };
534            CHECK(span.length() == 5);
535        }
536
537        // from non-const ptr and length
538        {
539            char ar[] = { 'H', 'e', 'l', 'l', 'o' };
540            char* ptr = ar;
541            cstring_span<> span{ ptr, 5 };
542            CHECK(span.length() == 5);
543        }
544
545        // from non-const ptr and length, 0 inside
546        {
547            char ar[] = { 'H', 'e', '\0', 'l', 'o' };
548            char* ptr = ar;
549            cstring_span<> span{ ptr, 5 };
550            CHECK(span.length() == 5);
551        }
552
553        // from const string
554        {
555            const std::string str = "Hello";
556            cstring_span<> span = str;
557            CHECK(span.length() == 5);
558        }
559
560        // from non-const string
561        {
562            std::string str = "Hello";
563            cstring_span<> span = str;
564            CHECK(span.length() == 5);
565        }
566
567        // from const vector
568        {
569            const std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
570            cstring_span<> span = vec;
571            CHECK(span.length() == 5);
572        }
573
574        // from non-const vector
575        {
576            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
577            cstring_span<> span = vec;
578            CHECK(span.length() == 5);
579        }
580
581        // from const span
582        {
583            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
584            const span<const char> inner = vec;
585            cstring_span<> span = inner;
586            CHECK(span.length() == 5);
587        }
588
589        // from non-const span
590        {
591            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
592            span<char> inner = vec;
593            cstring_span<> span = inner;
594            CHECK(span.length() == 5);
595        }
596
597        // from const string_span
598        {
599            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
600            cstring_span<> tmp = vec;
601            cstring_span<> span = tmp;
602            CHECK(span.length() == 5);
603        }
604
605        // from non-const string_span
606        {
607            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
608            string_span<> tmp = vec;
609            cstring_span<> span = tmp;
610            CHECK(span.length() == 5);
611        }
612
613        // creating string_span
614
615        // from string literal
616        {
617#ifdef CONFIRM_COMPILATION_ERRORS
618            string_span<> span = "Hello";
619#endif
620        }
621
622        // from const static array
623        {
624#ifdef CONFIRM_COMPILATION_ERRORS
625            const char ar[] = { 'H', 'e', 'l', 'l', 'o' };
626            string_span<> span = ar;
627            CHECK(span.length() == 5);
628#endif
629        }
630
631        // from non-const static array
632        {
633            char ar[] = { 'H', 'e', 'l', 'l', 'o' };
634            string_span<> span = ar;
635            CHECK(span.length() == 5);
636        }
637
638        // from const ptr and length
639        {
640#ifdef CONFIRM_COMPILATION_ERRORS
641            const char* ptr = "Hello";
642            string_span<> span{ ptr, 5 };
643            CHECK(span.length() == 5);
644#endif
645        }
646
647        // from non-const ptr and length
648        {
649            char ar[] = { 'H', 'e', 'l', 'l', 'o' };
650            char* ptr = ar;
651            string_span<> span{ ptr, 5 };
652            CHECK(span.length() == 5);
653        }
654
655        // from const string
656        {
657#ifdef CONFIRM_COMPILATION_ERRORS
658            const std::string str = "Hello";
659            string_span<> span = str;
660            CHECK(span.length() == 5);
661#endif
662        }
663
664        // from non-const string
665        {
666            std::string str = "Hello";
667            string_span<> span = str;
668            CHECK(span.length() == 5);
669        }
670
671        // from const vector
672        {
673#ifdef CONFIRM_COMPILATION_ERRORS
674            const std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
675            string_span<> span = vec;
676            CHECK(span.length() == 5);
677#endif
678        }
679
680        // from non-const vector
681        {
682            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
683            string_span<> span = vec;
684            CHECK(span.length() == 5);
685        }
686
687        // from const span
688        {
689#ifdef CONFIRM_COMPILATION_ERRORS
690            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
691            const span<const char> inner = vec;
692            string_span<> span = inner;
693            CHECK(span.length() == 5);
694#endif
695        }
696
697        // from non-const span
698        {
699            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
700            span<char> inner = vec;
701            string_span<> span = inner;
702            CHECK(span.length() == 5);
703        }
704
705        // from non-const span of non-const data from const vector
706        {
707#ifdef CONFIRM_COMPILATION_ERRORS
708            const std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
709            const span<char> inner = vec;
710            string_span<> span = inner;
711            CHECK(span.length() == 5);
712#endif
713        }
714
715        // from const string_span
716        {
717#ifdef CONFIRM_COMPILATION_ERRORS
718            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
719            cstring_span<> tmp = vec;
720            string_span<> span = tmp;
721            CHECK(span.length() == 5);
722#endif
723        }
724
725        // from non-const string_span
726        {
727            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
728            string_span<> tmp = vec;
729            string_span<> span = tmp;
730            CHECK(span.length() == 5);
731        }
732
733        // from non-const string_span from const vector
734        {
735#ifdef CONFIRM_COMPILATION_ERRORS
736            const std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
737            string_span<> tmp = vec;
738            string_span<> span = tmp;
739            CHECK(span.length() == 5);
740#endif
741        }
742
743        // from const string_span of non-const data
744        {
745            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
746            const string_span<> tmp = vec;
747            string_span<> span = tmp;
748            CHECK(span.length() == 5);
749        }
750    }
751
752    template<typename T>
753    T move_wrapper(T&& t)
754    {
755        return std::move(t);
756    }
757
758    template <class T>
759    T create() { return T{}; }
760
761    template <class T>
762    void use(basic_string_span<T, gsl::dynamic_extent> s) {}
763
764    TEST(MoveConstructors)
765    {
766        // move string_span
767        {
768            cstring_span<> span = "Hello";
769            auto span1 = std::move(span);
770            CHECK(span1.length() == 5);
771        }
772        {
773            cstring_span<> span = "Hello";
774            auto span1 = move_wrapper(std::move(span));
775            CHECK(span1.length() == 5);
776        }
777        {
778            cstring_span<> span = "Hello";
779            auto span1 = move_wrapper(std::move(span));
780            CHECK(span1.length() == 5);
781        }
782
783        // move span
784        {
785            span<const char> span = ensure_z("Hello");
786            cstring_span<> span1 = std::move(span);
787            CHECK(span1.length() == 5);
788        }
789        {
790            span<const char> span = ensure_z("Hello");
791            cstring_span<> span2 = move_wrapper(std::move(span));
792            CHECK(span2.length() == 5);
793        }
794
795        // move string
796        {
797#ifdef CONFIRM_COMPILATION_ERRORS
798            std::string str = "Hello";
799            string_span<> span = std::move(str);
800            CHECK(span.length() == 5);
801#endif
802        }
803        {
804#ifdef CONFIRM_COMPILATION_ERRORS
805            std::string str = "Hello";
806            string_span<> span = move_wrapper<std::string>(std::move(str));
807            CHECK(span.length() == 5);
808#endif
809        }
810        {
811#ifdef CONFIRM_COMPILATION_ERRORS
812            use<char>(create<string>());
813#endif
814        }
815
816        // move container
817        {
818#ifdef CONFIRM_COMPILATION_ERRORS
819            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
820            string_span<> span = std::move(vec);
821            CHECK(span.length() == 5);
822#endif
823        }
824        {
825#ifdef CONFIRM_COMPILATION_ERRORS
826            std::vector<char> vec = { 'H', 'e', 'l', 'l', 'o' };
827            string_span<> span = move_wrapper<std::vector<char>>(std::move(vec));
828            CHECK(span.length() == 5);
829#endif
830        }
831        {
832#ifdef CONFIRM_COMPILATION_ERRORS
833            use<char>(create<std::vector<char>>());
834#endif
835        }
836    }
837
838    TEST(Conversion)
839    {
840#ifdef CONFIRM_COMPILATION_ERRORS
841        cstring_span<> span = "Hello";
842        cwstring_span<> wspan{ span };
843        CHECK(wspan.length() == 5);
844#endif
845    }
846
847    czstring_span<> CreateTempName(string_span<> span)
848    {
849        Expects(span.size() > 1);
850
851        int last = 0;
852        if (span.size() > 4)
853        {
854            span[0] = 't';
855            span[1] = 'm';
856            span[2] = 'p';
857            last = 3;
858        }
859        span[last] = '\0';
860
861        auto ret = span.subspan(0, 4);
862        return{ ret };
863    }
864
865    TEST(zstring)
866    {
867
868        // create zspan from zero terminated string
869        {
870            char buf[1];
871            buf[0] = '\0';
872
873            zstring_span<> zspan({ buf, 1 });
874
875            CHECK(strlen(zspan.assume_z()) == 0);
876            CHECK(zspan.as_string_span().size() == 0);
877            CHECK(zspan.ensure_z().size() == 0);
878        }
879
880        // create zspan from non-zero terminated string
881        {
882            char buf[1];
883            buf[0] = 'a';
884
885            auto workaround_macro = [&]() { zstring_span<> zspan({ buf, 1 }); };
886            CHECK_THROW(workaround_macro(), fail_fast);
887        }
888
889        // usage scenario: create zero-terminated temp file name and pass to a legacy API
890        {
891            char buf[10];
892
893            auto name = CreateTempName({ buf, 10 });
894            if (!name.empty())
895            {
896                czstring<> str = name.assume_z();
897                CHECK(strlen(str) == 3);
898                CHECK(*(str+3) == '\0');
899            }
900        }
901
902    }
903
904    cwzstring_span<> CreateTempNameW(wstring_span<> span)
905    {
906        Expects(span.size() > 1);
907
908        int last = 0;
909        if (span.size() > 4)
910        {
911            span[0] = L't';
912            span[1] = L'm';
913            span[2] = L'p';
914            last = 3;
915        }
916        span[last] = L'\0';
917
918        auto ret = span.subspan(0, 4);
919        return{ ret };
920    }
921
922    TEST(wzstring)
923    {
924
925        // create zspan from zero terminated string
926        {
927            wchar_t buf[1];
928            buf[0] = L'\0';
929
930            wzstring_span<> zspan({ buf, 1 });
931
932            CHECK(wcsnlen(zspan.assume_z(), 1) == 0);
933            CHECK(zspan.as_string_span().size() == 0);
934            CHECK(zspan.ensure_z().size() == 0);
935        }
936
937        // create zspan from non-zero terminated string
938        {
939            wchar_t buf[1];
940            buf[0] = L'a';
941
942            auto workaround_macro = [&]() { wzstring_span<> zspan({ buf, 1 }); };
943            CHECK_THROW(workaround_macro(), fail_fast);
944        }
945
946        // usage scenario: create zero-terminated temp file name and pass to a legacy API
947        {
948            wchar_t buf[10];
949
950            auto name = CreateTempNameW({ buf, 10 });
951            if (!name.empty())
952            {
953                cwzstring<> str = name.assume_z();
954                CHECK(wcsnlen(str, 10) == 3);
955                CHECK(*(str + 3) == L'\0');
956            }
957        }
958    }
959
960    TEST(Issue305)
961    {
962        std::map<gsl::cstring_span<>, int> foo = { { "foo", 0 },{ "bar", 1 } };
963        CHECK(foo["foo"] == 0);
964        CHECK(foo["bar"] == 1);
965    }
966}
967
968int main(int, const char *[])
969{
970    return UnitTest::RunAllTests();
971}
972