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