190a62b1159b85597734dbde6d457815b8d103e9
[alexxy/gromacs.git] / src / gromacs / compat / tests / string_view.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2019, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 // Copyright 2017-2019 Martin Moene
36 //
37 // https://github.com/martinmoene/string-view-lite
38 //
39 // Distributed under the Boost Software License, Version 1.0.
40 // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
41 /*! \internal \file
42  * \brief Tests for C++14-compatible implementation of std::string_view.
43  *
44  * These tests are similer to those used in commit bf5824916b6895ccab0dbc2431520ee3b6d4f27f of
45  * https://github.com/martinmoene/string_view-lite.git. The code has not
46  * been linted with uncrustify so that any future updates to this
47  * active repo can be incorporated easily, and //NOLINT comments added
48  * to suppress clang-tidy warnings. The form of those
49  * changes have been made to simplify the contents, while making it
50  * easy to import any bug fixes that may appear in the source
51  * repository.
52  *
53  * \todo Remove when requiring C++17, which has a standardized version
54  * of std::string_view.
55  *
56  * \author Paul Bauer <paul.bauer.q@gmail.com>
57  * \ingroup module_compat
58  */
59 #include "gmxpre.h"
60
61 #include "gromacs/compat/string_view.h"
62
63 #include <initializer_list>
64 #include <iostream>
65 #include <string>
66 #include <utility>
67 #include <vector>
68
69 #include <gtest/gtest.h>
70
71 #include "gromacs/utility/strconvert.h"
72
73 // GMX modification to suppress Doxygen checking
74 #ifndef DOXYGEN
75
76 namespace gmx
77 {
78
79 using namespace compat;
80
81 namespace {
82
83 template< class T >
84 T * data( std::vector<T> & v )
85 {
86 #if nssv_CPP11_OR_GREATER
87     return v.data();
88 #else
89     return &v[0];
90 #endif
91 }
92
93 #define nssv_STD_SV_OR( expr )  ( nssv_USES_STD_STRING_VIEW || (expr) )
94
95 typedef string_view::size_type size_type;
96
97 // 24.4.2.1 Construction and assignment:
98
99 TEST(StringViewTest, CanDefaultConstructEmptyView)
100 {
101     SCOPED_TRACE( "string_view: Allows to default construct an empty string_view" );
102
103     string_view sv;
104
105     // use parenthesis with data() to prevent lest from using sv.data() as C-string:
106
107     EXPECT_TRUE(  sv.size() == size_type( 0 ) );
108     EXPECT_TRUE( (sv.data() == nssv_nullptr)  );
109 }
110
111 TEST(StringViewTest, CanConstructFromPointerAndSize)
112 {
113     SCOPED_TRACE( "string_view: Allows to construct from pointer and size" );
114
115     string_view sv( "hello world", 5 );
116
117     EXPECT_TRUE(   sv.size() == size_type( 5 ) );
118     EXPECT_TRUE( *(sv.data() + 0) == 'h'       );
119     EXPECT_TRUE( *(sv.data() + 4) == 'o'       );
120 }
121
122 TEST(StringViewTest, CanConstructFromCString)
123 {
124     SCOPED_TRACE( "string_view: Allows to construct from C-string" );
125
126     string_view sv( "hello world" );
127
128     EXPECT_TRUE(   sv.size() == size_type( 11 ) );
129     EXPECT_TRUE( *(sv.data() +  0) == 'h'       );
130     EXPECT_TRUE( *(sv.data() + 10) == 'd'       );
131 }
132
133 TEST(StringViewTest, CanCopyConstructFromEmptyView)
134 {
135     SCOPED_TRACE( "string_view: Allows to copy-construct from empty string_view" );
136
137     string_view sv1;
138
139     string_view sv2( sv1 );
140
141     // use parenthesis with data() to prevent lest from using sv.data() as C-string:
142
143     EXPECT_TRUE(  sv2.size() == size_type( 0 ) );
144     EXPECT_TRUE( (sv2.data() == nssv_nullptr)  );
145 }
146
147 TEST(StringViewTest, CanCopyConstructFromNonEmptyView)
148 {
149     SCOPED_TRACE( "string_view: Allows to copy-construct from non-empty string_view" );
150
151     string_view sv1( "hello world", 5 );
152
153     string_view sv2( sv1 );
154
155     EXPECT_TRUE(   sv2.size()      == sv1.size()  );
156     EXPECT_TRUE(  (sv2.data()      == sv1.data()) );
157     EXPECT_TRUE( *(sv2.data() + 0) == 'h'         );
158     EXPECT_TRUE( *(sv2.data() + 4) == 'o'         );
159 }
160
161 // Assignment:
162
163 TEST(StringViewTest, CanCopyAssingFromEmptyView)
164 {
165     SCOPED_TRACE( "string_view: Allows to copy-assign from empty string_view" );
166
167     string_view sv1;
168     string_view sv2;
169
170     sv2 = sv1;
171
172     // use parenthesis with data() to prevent lest from using sv.data() as C-string:
173
174     EXPECT_TRUE(  sv2.size() == size_type( 0 ) );
175     EXPECT_TRUE( (sv2.data() == nssv_nullptr) );
176 }
177
178 TEST(StringViewTest, CanCopyAssingFromNonEmptyView)
179 {
180     SCOPED_TRACE( "string_view: Allows to copy-assign from non-empty string_view" );
181
182     string_view sv1( "hello world", 5 );
183     string_view sv2;
184
185     sv2 = sv1;
186
187     // use parenthesis with data() to prevent lest from using sv.data() as C-string:
188
189     EXPECT_TRUE(   sv2.size()      == sv1.size()  );
190     EXPECT_TRUE(  (sv2.data()      == sv1.data()) );
191     EXPECT_TRUE( *(sv2.data() + 0) == 'h'         );
192     EXPECT_TRUE( *(sv2.data() + 4) == 'o'         );
193 }
194
195 // 24.4.2.2 Iterator support:
196
197 TEST(StringViewTest, AllowForwardIteration)
198 {
199     SCOPED_TRACE( "string_view: Allows forward iteration" );
200
201     char hello[] = "hello";
202     string_view sv( hello );
203
204     for ( string_view::iterator pos = sv.begin(); pos != sv.end(); ++pos )
205     {
206         typedef std::iterator_traits< string_view::iterator >::difference_type difference_type;
207
208         difference_type i = std::distance( sv.begin(), pos );
209         EXPECT_TRUE( *pos == *(sv.data() + i) );
210     }
211 }
212
213 TEST(StringViewTest, AllowConstForwardIteration)
214 {
215     SCOPED_TRACE( "string_view: Allows const forward iteration" );
216
217     char hello[] = "hello";
218     string_view sv( hello );
219
220     for ( string_view::const_iterator pos = sv.begin(); pos != sv.end(); ++pos )
221     {
222         typedef std::iterator_traits< string_view::const_iterator >::difference_type difference_type;
223
224         difference_type i = std::distance( sv.cbegin(), pos );
225         EXPECT_TRUE( *pos == *(sv.data() + i) );
226     }
227 }
228
229 TEST(StringViewTest, AllowReverseIteration)
230 {
231     SCOPED_TRACE( "string_view: Allows reverse iteration" );
232
233     char hello[] = "hello";
234     string_view sv( hello );
235
236     for ( string_view::reverse_iterator pos = sv.rbegin(); pos != sv.rend(); ++pos )
237     {
238         typedef std::iterator_traits< string_view::reverse_iterator >::difference_type difference_type;
239
240         difference_type dist = std::distance( sv.rbegin(), pos );
241         EXPECT_TRUE( *pos == *(sv.data() + sv.size() - 1 - dist) );
242     }
243 }
244
245 TEST(StringViewTest, AllowConstReverseIteration)
246 {
247     SCOPED_TRACE( "string_view: Allows const reverse iteration" );
248
249     char hello[] = "hello";
250     string_view sv( hello );
251
252     for ( string_view::const_reverse_iterator pos = sv.crbegin(); pos != sv.crend(); ++pos )
253     {
254         typedef std::iterator_traits< string_view::const_reverse_iterator >::difference_type difference_type;
255
256         difference_type  dist = std::distance( sv.crbegin(), pos );
257         EXPECT_TRUE( *pos == *(sv.data() + sv.size() - 1 - dist) );
258     }
259 }
260
261 // 24.4.2.3 Capacity:
262
263 TEST(StringViewTest, CanObtainSizeFromViewViaSize)
264 {
265     SCOPED_TRACE( "string_view: Allows to obtain the size of the view via size()" );
266
267     char hello[] = "hello";
268     string_view sv( hello );
269
270     EXPECT_TRUE( sv.size() == std::char_traits<char>::length(hello) );
271 }
272
273 TEST(StringViewTest, CanObtainSizeFromViewViaLength)
274 {
275     SCOPED_TRACE( "string_view: Allows to obtain the size of the view via length()" );
276
277     char hello[] = "hello";
278     string_view sv( hello );
279
280     EXPECT_TRUE( sv.length() == std::char_traits<char>::length(hello) );
281 }
282
283 TEST(StringViewTest, CanObtainMaxSizeViaMaxSize)
284 {
285     SCOPED_TRACE( "string_view: Allows to obtain the maximum size a view can be via max_size()" );
286
287     // "large"
288     EXPECT_TRUE( string_view().max_size() >= (std::numeric_limits< string_view::size_type >::max)() / 10 );
289 }
290
291 TEST(StringViewTest, CanCheckForEmptyStringWithEmpty)
292 {
293     SCOPED_TRACE( "string_view: Allows to check for an empty string_view via empty()" );
294
295     string_view sve;
296     string_view svne("hello");
297
298     EXPECT_TRUE(      sve.size() == size_type( 0 ) );
299     EXPECT_TRUE(      sve.empty() );
300     EXPECT_FALSE( svne.empty() );
301 }
302
303 // 24.4.2.4 Element access:
304
305 TEST(StringViewTest, CanAccessElementViaArrayIndex)
306 {
307     SCOPED_TRACE( "string_view: Allows to observe an element via array indexing" );
308
309     // Requires: index < sv.size()
310
311     char hello[] = "hello";
312     string_view sv( hello );
313
314     for ( size_type i = 0; i < sv.size(); ++i )
315     {
316         EXPECT_TRUE( sv[i] == hello[i] );
317     }
318 }
319
320 TEST(StringViewTest, CanAccessElementViaAt)
321 {
322     SCOPED_TRACE( "string_view: Allows to observe an element via at()" );
323
324     char hello[] = "hello";
325     string_view sv( hello );
326
327     for ( size_type i = 0; i < sv.size(); ++i )
328     {
329         EXPECT_TRUE( sv.at(i) == hello[i] );
330     }
331 }
332
333 TEST(StringViewTest, ThrowsOnOutOfBoundsAccess)
334 {
335     SCOPED_TRACE( "string_view: Throws at observing an element via at() with an index of size() or larger" );
336
337     string_view sv("hello");
338
339     EXPECT_ANY_THROW(   sv.at( sv.size()     ) );
340     EXPECT_NO_THROW( sv.at( sv.size() - 1 ) );
341 }
342
343 TEST(StringViewTest, CanAccessAllElementsViaData)
344 {
345     SCOPED_TRACE( "string_view: Allows to observe elements via data()" );
346
347     char hello[] = "hello";
348     string_view sv( hello );
349
350     EXPECT_TRUE( *sv.data() == *sv.begin() );
351
352     for ( size_type i = 0; i < sv.size(); ++i )
353     {
354         EXPECT_TRUE( sv.data()[i] == hello[i] );
355     }
356 }
357
358 TEST(StringViewTest, DataFromEmptyStringIsNullptr)
359 {
360     SCOPED_TRACE( "string_view: Yields nullptr (or NULL) with data() for an empty string_view" );
361
362     string_view sv;
363
364     // use parenthesis with data() to prevent lest from using sv.data() as C-string:
365
366     EXPECT_TRUE( (sv.data() == nssv_nullptr) );
367 }
368
369 // 24.4.2.5 Modifiers:
370
371 TEST(StringViewTest, CanRemovePrefix)
372 {
373     SCOPED_TRACE( "string_view: Allows to remove a prefix of n elements" );
374
375     char hello[] = "hello world";
376     string_view sv( hello );
377
378     sv.remove_prefix( 6 );
379
380     EXPECT_TRUE( sv.size() == size_type( 5 ) );
381     EXPECT_TRUE( std::equal( sv.begin(), sv.end(), hello + 6) );
382 }
383
384 TEST(StringViewTest, CanRemoveSuffix)
385 {
386     SCOPED_TRACE( "string_view: Allows to remove a suffix of n elements" );
387
388     char hello[] = "hello world";
389     string_view sv( hello );
390
391     sv.remove_suffix( 6 );
392
393     EXPECT_TRUE( sv.size() == size_type( 5 ) );
394     EXPECT_TRUE( std::equal( sv.begin(), sv.end(), hello ) );
395 }
396
397 TEST(StringViewTest, CanSwapWithOtherView)
398 {
399     SCOPED_TRACE( "string_view: Allows to swap with other string_view" );
400
401     char hello[]  = "hello";
402     char world[]  = "world";
403     string_view sv1( hello );
404     string_view sv2( world );
405
406     sv1.swap( sv2 );
407
408     EXPECT_TRUE( std::equal( sv1.begin(), sv1.end(), world )  );
409     EXPECT_TRUE( std::equal( sv2.begin(), sv2.end(), hello )  );
410 }
411
412 // 24.4.2.6 String operations:
413
414 TEST(StringViewTest, CanCopySubstringWithCopy)
415 {
416     SCOPED_TRACE( "string_view: Allows to copy a substring of length n, starting at position pos (default: 0) via copy()" );
417
418     char hello[]  = "hello world";
419     string_view sv( hello );
420
421     {
422         std::vector<string_view::value_type> vec( sv.size() );
423
424         sv.copy( data(vec), vec.size() );
425
426         EXPECT_TRUE( std::equal( vec.begin(), vec.end(), hello )  );
427     }{
428         std::size_t offset = 3u; std::size_t length = 4u;
429         std::vector<string_view::value_type> vec( length );
430
431         sv.copy( data(vec), length, offset );
432
433         EXPECT_TRUE( std::equal( vec.begin(), vec.end(), hello + offset )  );
434     }
435 }
436
437 TEST(StringViewTest, ThrowsOnOutOfBoundsCopy)
438 {
439     SCOPED_TRACE( "string_view: Throws if requested position of copy() exceeds string_view's size()" );
440
441     string_view sv("hello world");
442     std::vector<string_view::value_type> vec( sv.size() );
443
444     EXPECT_ANY_THROW(   sv.copy( data(vec), sv.size() - 4, sv.size() + 1 ) );
445     EXPECT_NO_THROW( sv.copy( data(vec), sv.size() - 4, sv.size() + 0 ) );
446 }
447
448 TEST(StringViewTest, CanObtainSubstringWithSubstr)
449 {
450     SCOPED_TRACE( "string_view: Allow to obtain a sub string, starting at position pos (default: 0) and of length n (default full), via substr()" );
451
452     char hello[] = "hello world";
453     string_view sv( hello );
454
455     {
456 #if nssv_USES_STD_STRING_VIEW && defined(__GNUC__)
457         EXPECT_TRUE( !!"std::string_view::substr(), with default pos, count is not available with GNU C" );
458 #else
459         EXPECT_TRUE( std::equal( sv.begin(), sv.end(), sv.substr().begin() ) );
460 #endif
461     }{
462         string_view subv = sv.substr( 6 );
463
464         EXPECT_TRUE( std::equal( subv.begin(), subv.end(), hello + 6 ) );
465     }{
466         string_view subv = sv.substr( 3, 4 );
467
468         EXPECT_TRUE( std::equal( subv.begin(), subv.end(), hello + 3 ) );
469     }
470 }
471
472 TEST(StringViewTest, ThrowsOnOutOfBoundsSubstr)
473 {
474     SCOPED_TRACE( "string_view: Throws if requested position of substr() exceeds string_view's size()" );
475
476     string_view sv("hello world");
477
478     EXPECT_ANY_THROW(   sv.substr( sv.size() + 1 ) );
479     EXPECT_NO_THROW( sv.substr( sv.size() + 0 ) );
480 }
481
482 TEST(StringViewTest, CanLexicallyCompareViewWithCompare)
483 {
484     SCOPED_TRACE( "string_view: Allows to lexically compare to another string_view via compare(), (1)" );
485
486     char hello[] = "hello";
487     char world[] = "world";
488
489     EXPECT_TRUE( string_view( hello ).compare( string_view( hello ) ) == 0 );
490     EXPECT_TRUE( string_view( hello ).compare( string_view( world ) ) <  0 );
491     EXPECT_TRUE( string_view( world ).compare( string_view( hello ) ) >  0 );
492
493     char hello_sp[] = "hello ";
494
495     EXPECT_TRUE( string_view( hello    ).compare( string_view( hello_sp ) ) < 0 );
496     EXPECT_TRUE( string_view( hello_sp ).compare( string_view( hello    ) ) > 0 );
497 }
498
499 TEST(StringViewTest, CanCompareEmptyViewsWIthCompare)
500 {
501     SCOPED_TRACE( "string_view: Allows to compare empty string_views as equal via compare(), (1)" );
502
503     EXPECT_TRUE( string_view().compare( string_view() ) == 0 );
504 }
505
506 TEST(StringViewTest, CanCompareSubStringWithViewViaCompare)
507 {
508     SCOPED_TRACE( "string_view: Allows to compare a sub string to another string_view via compare(), (2)" );
509
510     string_view sv1("hello world");
511     string_view sv2("world");
512
513     EXPECT_TRUE( sv1.compare ( 0, sv1.length(), sv1 ) == 0 );
514     EXPECT_TRUE( sv1.compare ( 6, 5, sv2 ) == 0 );
515     EXPECT_TRUE( sv1.compare ( 0, 5, sv2 ) <  0 );
516     EXPECT_TRUE( sv2.compare ( 0, 5, sv1 ) >  0 );
517 }
518
519 TEST(StringViewTest, CanCompareSubStringWithSubStringViewViaCompare)
520 {
521     SCOPED_TRACE( "string_view: Allows to compare a sub string to another string_view sub string via compare(), (3)" );
522
523     string_view sv1("hello world");
524
525     EXPECT_TRUE( sv1.compare ( 0, sv1.length(), sv1 ) == 0 );
526     EXPECT_TRUE( sv1.compare ( 6, 5, sv1, 6, 5 ) ==  0 );
527     EXPECT_TRUE( sv1.compare ( 0, 5, sv1, 6, 5 )  <  0 );
528     EXPECT_TRUE( sv1.compare ( 6, 5, sv1, 0, 5 )  >  0 );
529 }
530
531 TEST(StringViewTest, CanCompareToCStringViaCompare)
532 {
533     SCOPED_TRACE( "string_view: Allows to compare to a C-string via compare(), (4)" );
534
535     char hello[] = "hello";
536     char world[] = "world";
537
538     EXPECT_TRUE( string_view( hello ).compare( hello ) == 0 );
539     EXPECT_TRUE( string_view( hello ).compare( world ) <  0 );
540     EXPECT_TRUE( string_view( world ).compare( hello ) >  0 );
541 }
542
543 TEST(StringViewTest, CanCompareSubStringToCStringViaCompare)
544 {
545     SCOPED_TRACE( "string_view: Allows to compare a sub string to a C-string via compare(), (5)" );
546
547     char hello[] = "hello world";
548     char world[] = "world";
549
550     EXPECT_TRUE( string_view( hello ).compare( 6, 5, world ) == 0 );
551     EXPECT_TRUE( string_view( hello ).compare( world ) <  0 );
552     EXPECT_TRUE( string_view( world ).compare( hello ) >  0 );
553 }
554
555 TEST(StringViewTest, CanCompareSubStringToCStringPrefixViaCompare)
556 {
557     SCOPED_TRACE( "string_view: Allows to compare a sub string to a C-string prefix via compare(), (6)" );
558
559     char hello[] = "hello world";
560     char world[] = "world";
561
562     EXPECT_TRUE( string_view( hello ).compare( 6, 5, world, 5 ) == 0 );
563     EXPECT_TRUE( string_view( hello ).compare( 0, 5, world, 5 ) <  0 );
564     EXPECT_TRUE( string_view( hello ).compare( 6, 5, hello, 5 ) >  0 );
565 }
566
567 // 24.4.2.7 Searching:
568
569 #if nssv_HAVE_STARTS_WITH
570
571 TEST(StringViewTest, CanCheckForPrefixViewViaStartsWith)
572 {
573     SCOPED_TRACE( "string_view: Allows to check for a prefix string_view via starts_with(), (1)" );
574
575     char hello[] = "hello world";
576
577     EXPECT_TRUE(     string_view( hello ).starts_with( string_view( hello ) ) );
578     EXPECT_TRUE(     string_view( hello ).starts_with( string_view("hello") ) );
579     EXPECT_FALSE( string_view( hello ).starts_with( string_view("world") ) );
580 }
581
582 TEST(StringViewTest, CanCheckForPrefixCharacterViaStartsWith)
583 {
584     SCOPED_TRACE( "string_view: Allows to check for a prefix character via starts_with(), (2)" );
585
586     char hello[] = "hello world";
587
588     EXPECT_TRUE(     string_view( hello ).starts_with( 'h' ) );
589     EXPECT_FALSE( string_view( hello ).starts_with( 'e' ) );
590 }
591
592 TEST(StringViewTest, CanCheckForPrefixCStringViaStartsWith)
593 {
594     SCOPED_TRACE( "string_view: Allows to check for a prefix C-string via starts_with(), (3)" );
595
596     char hello[] = "hello world";
597
598     EXPECT_TRUE(     string_view( hello ).starts_with( hello ) );
599     EXPECT_TRUE(     string_view( hello ).starts_with("hello") );
600     EXPECT_FALSE( string_view( hello ).starts_with("world") );
601 }
602
603 #endif // nssv_HAVE_STARTS_WITH
604
605 #if nssv_HAVE_ENDS_WITH
606
607 TEST(StringViewTest, CanCheckForSuffixViewViaEndsWith)
608 {
609     SCOPED_TRACE( "string_view: Allows to check for a suffix string_view via ends_with(), (1)" );
610
611     char hello[] = "hello world";
612
613     EXPECT_TRUE(     string_view( hello ).ends_with( string_view( hello ) ) );
614     EXPECT_TRUE(     string_view( hello ).ends_with( string_view("world") ) );
615     EXPECT_FALSE( string_view( hello ).ends_with( string_view("hello") ) );
616 }
617
618 TEST(StringViewTest, CanCheckForSuffixCharacterViaEndsWith)
619 {
620     SCOPED_TRACE( "string_view: Allows to check for a suffix character via ends_with(), (2)" );
621
622     char hello[] = "hello world";
623
624     EXPECT_TRUE(     string_view( hello ).ends_with( 'd' ) );
625     EXPECT_FALSE( string_view( hello ).ends_with( 'l' ) );
626 }
627
628 TEST(StringViewTest, CanCheckForSuffixCStringViaEndsWith)
629 {
630     SCOPED_TRACE( "string_view: Allows to check for a suffix C-string via ends_with(), (3)" );
631
632     char hello[] = "hello world";
633
634     EXPECT_TRUE(     string_view( hello ).ends_with( hello ) );
635     EXPECT_TRUE(     string_view( hello ).ends_with("world") );
636     EXPECT_FALSE( string_view( hello ).ends_with("hello") );
637 }
638
639 #endif // nssv_HAVE_ENDS_WITH
640
641 TEST(StringViewTest, CanSearchForViewSubstrViaFind)
642 {
643     SCOPED_TRACE( "string_view: Allows to search for a string_view substring, starting at position pos (default: 0) via find(), (1)" );
644
645     char hello[] = "hello world";
646     string_view sv( hello );
647
648     EXPECT_TRUE( sv.find( sv    ) == size_type( 0 ) );
649     EXPECT_TRUE( sv.find( sv, 1 ) == string_view::npos );
650     EXPECT_TRUE( sv.find( string_view("world" )    ) == size_type( 6 ) );
651     EXPECT_TRUE( sv.find( string_view("world" ), 6 ) == size_type( 6 ) );
652     EXPECT_TRUE( sv.find( string_view("world" ), 7 ) == string_view::npos );
653 }
654
655 TEST(StringViewTest, CanSearchForCharacterViaFind)
656 {
657     SCOPED_TRACE( "string_view: Allows to search for a character, starting at position pos (default: 0) via find(), (2)" );
658
659     char hello[] = "hello world";
660     string_view sv( hello );
661
662     EXPECT_TRUE( sv.find('h'    ) == size_type( 0 )    );
663     EXPECT_TRUE( sv.find('h', 1 ) == string_view::npos );
664     EXPECT_TRUE( sv.find('w'    ) == size_type( 6 )    );
665     EXPECT_TRUE( sv.find('w', 6 ) == size_type( 6 )    );
666     EXPECT_TRUE( sv.find('w', 7 ) == string_view::npos );
667 }
668
669 TEST(StringViewTest, CanSearchForCStringSubstringViaFind)
670 {
671     SCOPED_TRACE( "string_view: Allows to search for a C-string substring, starting at position pos and of length n via find(), (3)" );
672
673     char hello[] = "hello world";
674     string_view sv( hello );
675
676     EXPECT_TRUE( sv.find( hello , 0, sv.size() ) == size_type( 0 )    );
677     EXPECT_TRUE( sv.find( hello , 1, sv.size() ) == string_view::npos );
678     EXPECT_TRUE( sv.find("world", 0, 5 ) == size_type( 6 )    );
679     EXPECT_TRUE( sv.find("world", 6, 5 ) == size_type( 6 )    );
680     EXPECT_TRUE( sv.find("world", 7, 4 ) == string_view::npos );
681     EXPECT_TRUE( sv.find("world", 3, 0 ) == size_type( 3 )    );
682 }
683
684 TEST(StringViewTest, CanSearchForCStringSubstringViaFindWithDefaultPos)
685 {
686     SCOPED_TRACE( "string_view: Allows to search for a C-string substring, starting at position pos (default: 0) via find(), (4)" );
687
688     char hello[] = "hello world";
689     string_view sv( hello );
690
691     EXPECT_TRUE( sv.find( hello     ) == size_type( 0 )    );
692     EXPECT_TRUE( sv.find( hello , 1 ) == string_view::npos );
693     EXPECT_TRUE( sv.find("world"    ) == size_type( 6 )    );
694     EXPECT_TRUE( sv.find("world", 6 ) == size_type( 6 )    );
695     EXPECT_TRUE( sv.find("world", 7 ) == string_view::npos );
696 }
697
698 TEST(StringViewTest, CanBackwardsSearchForViewSubstrViaFind)
699 {
700     SCOPED_TRACE( "string_view: Allows to search backwards for a string_view substring, starting at position pos (default: npos) via rfind(), (1)" );
701
702     char hello[] = "hello world";
703     string_view sv( hello );
704
705     EXPECT_TRUE( sv.rfind( sv    ) == size_type( 0 ) );
706     EXPECT_TRUE( sv.rfind( sv, 3 ) == size_type( 0 ) );
707     EXPECT_TRUE( sv.rfind( string_view(        )    ) == size_type(11 ) );
708     EXPECT_TRUE( sv.rfind( string_view("world" )    ) == size_type( 6 ) );
709     EXPECT_TRUE( sv.rfind( string_view("world" ), 6 ) == size_type( 6 ) );
710     EXPECT_TRUE( sv.rfind( string_view("world" ), 5 ) == string_view::npos );
711     EXPECT_TRUE( sv.rfind( string_view("hello world, a longer text" ) ) == string_view::npos );
712 }
713
714 TEST(StringViewTest, CanBackwardsSearchForCharacterViaFind)
715 {
716     SCOPED_TRACE( "string_view: Allows to search backwards for a character, starting at position pos (default: npos) via rfind(), (2)" );
717
718     char hello[] = "hello world";
719     string_view sv( hello );
720
721     EXPECT_TRUE( sv.rfind('h'    ) == size_type( 0 )    );
722     EXPECT_TRUE( sv.rfind('e'    ) == size_type( 1 )    );
723     EXPECT_TRUE( sv.rfind('e', 0 ) == string_view::npos );
724     EXPECT_TRUE( sv.rfind('w'    ) == size_type( 6 )    );
725     EXPECT_TRUE( sv.rfind('w', 6 ) == size_type( 6 )    );
726     EXPECT_TRUE( sv.rfind('w', 5 ) == string_view::npos );
727 }
728
729 TEST(StringViewTest, CanBackwardsSearchForCStringSubstringViaFind)
730 {
731     SCOPED_TRACE( "string_view: Allows to search backwards for a C-string substring, starting at position pos and of length n via rfind(), (3)" );
732
733     char hello[] = "hello world";
734     string_view sv( hello );
735
736     EXPECT_TRUE( sv.rfind( hello         ) == size_type( 0 ) );
737     EXPECT_TRUE( sv.rfind( hello ,  0, 5 ) == size_type( 0 ) );
738     EXPECT_TRUE( sv.rfind( hello ,  1, 5 ) == size_type( 0 ) );
739     EXPECT_TRUE( sv.rfind("world", 10, 5 ) == size_type( 6 ) );
740     EXPECT_TRUE( sv.rfind("world",  6, 5 ) == size_type( 6 ) );
741     EXPECT_TRUE( sv.rfind("world",  5, 5 ) == string_view::npos );
742 }
743
744 TEST(StringViewTest, CanBackwardsSearchForCStringSubstringViaFindWithDefaultPos)
745 {
746     SCOPED_TRACE( "string_view: Allows to search backwards for a C-string substring, starting at position pos (default: 0) via rfind(), (4)" );
747
748     char hello[] = "hello world";
749     string_view sv( hello );
750
751     EXPECT_TRUE( sv.rfind( hello     ) == size_type( 0 ) );
752     EXPECT_TRUE( sv.rfind( hello , 3 ) == size_type( 0 ) );
753     EXPECT_TRUE( sv.rfind("world"    ) == size_type( 6 ) );
754     EXPECT_TRUE( sv.rfind("world", 6 ) == size_type( 6 ) );
755     EXPECT_TRUE( sv.rfind("world", 5 ) == string_view::npos );
756 }
757
758 TEST(StringViewTest, CanSearchForFirstOccurenceOfAnyCharacterInView)
759 {
760     SCOPED_TRACE( "string_view: Allows to search for the first occurrence of any of the characters specified in a string view, starting at position pos (default: 0) via find_first_of(), (1)" );
761
762     char hello[] = "hello world";
763     string_view sv( hello );
764
765     EXPECT_TRUE( sv.find_first_of( sv    ) == size_type( 0 ) );
766     EXPECT_TRUE( sv.find_first_of( sv, 3 ) == size_type( 3 ) );
767     EXPECT_TRUE( sv.find_first_of( string_view("xwo" )    ) == size_type( 4 ) );
768     EXPECT_TRUE( sv.find_first_of( string_view("wdx" ), 6 ) == size_type( 6 ) );
769     EXPECT_TRUE( sv.find_first_of( string_view("wxy" ), 7 ) == string_view::npos );
770 }
771
772 TEST(StringViewTest, CanSearchForFirstOccurenceOfCharacter)
773 {
774     SCOPED_TRACE( "string_view: Allows to search for a character, starting at position pos (default: 0) via find_first_of(), (2)" );
775
776     char hello[] = "hello world";
777     string_view sv( hello );
778
779     EXPECT_TRUE( sv.find_first_of('h'    ) == size_type( 0 )    );
780     EXPECT_TRUE( sv.find_first_of('h', 1 ) == string_view::npos );
781     EXPECT_TRUE( sv.find_first_of('w'    ) == size_type( 6 )    );
782     EXPECT_TRUE( sv.find_first_of('w', 6 ) == size_type( 6 )    );
783     EXPECT_TRUE( sv.find_first_of('w', 7 ) == string_view::npos );
784 }
785
786 TEST(StringViewTest, CanSearchForFirstOccurenceOfCharactersInCStringInLenght)
787 {
788     SCOPED_TRACE( "string_view: Allows to search for the first occurrence of any of the characters specified in a C-string, starting at position pos and of length n via find_first_of(), (3)" );
789
790     char hello[] = "hello world";
791     string_view sv( hello );
792
793     EXPECT_TRUE( sv.find_first_of( hello , 0, sv.size() ) == size_type( 0 ) );
794     EXPECT_TRUE( sv.find_first_of( hello , 1, sv.size() ) == size_type( 1 ) );
795     EXPECT_TRUE( sv.find_first_of(  "xwy", 0, 3 ) == size_type( 6 )    );
796     EXPECT_TRUE( sv.find_first_of(  "xwy", 6, 3 ) == size_type( 6 )    );
797     EXPECT_TRUE( sv.find_first_of(  "xwy", 7, 3 ) == string_view::npos );
798     EXPECT_TRUE( sv.find_first_of(  "xyw", 0, 2 ) == string_view::npos );
799 }
800
801 TEST(StringViewTest, CanSearchForFirstOccurenceOfCharactersInCString)
802 {
803     SCOPED_TRACE( "string_view: Allows to search for the first occurrence of any of the characters specified in a C-string, starting at position pos via find_first_of(), (4)" );
804
805     char hello[] = "hello world";
806     string_view sv( hello );
807
808     EXPECT_TRUE( sv.find_first_of( hello , 0 ) == size_type( 0 )    );
809     EXPECT_TRUE( sv.find_first_of( hello , 1 ) == size_type( 1 )    );
810     EXPECT_TRUE( sv.find_first_of(  "xwy", 0 ) == size_type( 6 )    );
811     EXPECT_TRUE( sv.find_first_of(  "xwy", 6 ) == size_type( 6 )    );
812     EXPECT_TRUE( sv.find_first_of(  "xwy", 7 ) == string_view::npos );
813 }
814
815 TEST(StringViewTest, CanBackwardsSearchForLastOccurenceOfAnyCharacterInView)
816 {
817     SCOPED_TRACE( "string_view: Allows to search backwards for the last occurrence of any of the characters specified in a string view, starting at position pos (default: npos) via find_last_of(), (1)" );
818
819     char hello[] = "hello world";
820     char empty[] = "";
821     string_view sv( hello );
822     string_view sve( empty );
823
824     EXPECT_TRUE( sv.find_last_of( sv    ) == size_type( 10 ) );
825     EXPECT_TRUE( sv.find_last_of( sv, 3 ) == size_type(  3 ) );
826     EXPECT_TRUE( sv.find_last_of( string_view("xwo" )    ) == size_type( 7 ) );
827     EXPECT_TRUE( sv.find_last_of( string_view("wdx" ), 6 ) == size_type( 6 ) );
828     EXPECT_TRUE( sv.find_last_of( string_view("wxy" ), 7 ) == size_type( 6 ) );
829
830     EXPECT_TRUE( sve.find_last_of( string_view("x") ) == string_view::npos );    // issue 20 (endless loop)
831 }
832
833 TEST(StringViewTest, CanBackwardsSearchForLastOccurenceOfCharacter)
834 {
835     SCOPED_TRACE( "string_view: Allows to search backwards for a character, starting at position pos (default: 0) via find_last_of(), (2)" );
836
837     char hello[] = "hello world";
838     string_view sv( hello );
839
840     EXPECT_TRUE( sv.find_last_of('h'    ) == size_type( 0 )    );
841     EXPECT_TRUE( sv.find_last_of('l', 1 ) == string_view::npos );
842     EXPECT_TRUE( sv.find_last_of('w'    ) == size_type( 6 )    );
843     EXPECT_TRUE( sv.find_last_of('w', 6 ) == size_type( 6 )    );
844     EXPECT_TRUE( sv.find_last_of('w', 5 ) == string_view::npos );
845 }
846
847 TEST(StringViewTest, CanBackwardsSearchForLastOccurenceOfCharactersInCStringInLenght)
848 {
849     SCOPED_TRACE( "string_view: Allows to search backwards for the first occurrence of any of the characters specified in a C-string, starting at position pos and of length n via find_last_of(), (3)" );
850
851     char hello[] = "hello world";
852     string_view sv( hello );
853
854     EXPECT_TRUE( sv.find_last_of( hello , 0, sv.size() ) == size_type( 0 ) );
855     EXPECT_TRUE( sv.find_last_of( hello , 1, sv.size() ) == size_type( 1 ) );
856     EXPECT_TRUE( sv.find_last_of("xwy", 10, 3 ) == size_type( 6 )    );
857     EXPECT_TRUE( sv.find_last_of("xwy",  6, 3 ) == size_type( 6 )    );
858     EXPECT_TRUE( sv.find_last_of("xwy",  5, 3 ) == string_view::npos );
859     EXPECT_TRUE( sv.find_last_of("xyw", 10, 2 ) == string_view::npos );
860 }
861
862 TEST(StringViewTest, CanBackwardsSearchForLastOccurenceOfCharactersInCString)
863 {
864     SCOPED_TRACE( "string_view: Allows to search backwards for the first occurrence of any of the characters specified in a C-string, starting at position pos via find_last_of(), (4)" );
865
866     char hello[] = "hello world";
867     string_view sv( hello );
868
869     EXPECT_TRUE( sv.find_last_of( hello ,  0 ) == size_type( 0 )    );
870     EXPECT_TRUE( sv.find_last_of( hello ,  1 ) == size_type( 1 )    );
871     EXPECT_TRUE( sv.find_last_of(  "xwy", 10 ) == size_type( 6 )    );
872     EXPECT_TRUE( sv.find_last_of(  "xwy",  6 ) == size_type( 6 )    );
873     EXPECT_TRUE( sv.find_last_of(  "xwy",  5 ) == string_view::npos );
874 }
875
876 TEST(StringViewTest, CanSearchForFirstNotFoundCharacter)
877 {
878     SCOPED_TRACE( "string_view: Allows to search for the first character not specified in a string view, starting at position pos (default: 0) via find_first_not_of(), (1)" );
879
880     char hello[] = "hello world";
881     string_view sv( hello );
882
883     EXPECT_TRUE( sv.find_first_not_of( sv    ) == string_view::npos );
884     EXPECT_TRUE( sv.find_first_not_of( sv, 3 ) == string_view::npos );
885     EXPECT_TRUE( sv.find_first_not_of( string_view("helo "   )    ) == size_type(  6 ) );
886     EXPECT_TRUE( sv.find_first_not_of( string_view("helo "   ), 6 ) == size_type(  6 ) );
887     EXPECT_TRUE( sv.find_first_not_of( string_view("helo "   ), 7 ) == size_type(  8 ) );
888     EXPECT_TRUE( sv.find_first_not_of( string_view("helo wr" )    ) == size_type( 10 ) );
889 }
890
891 TEST(StringViewTest, CanSearchForFirstNonMatchingCharacter)
892 {
893     SCOPED_TRACE( "string_view: Allows to search for the first character not equal to the specified character, starting at position pos (default: 0) via find_first_not_of(), (2)" );
894
895     char hello[] = "hello world";
896     string_view sv( hello );
897
898     EXPECT_TRUE( sv.find_first_not_of('h'     ) == size_type( 1 )    );
899     EXPECT_TRUE( sv.find_first_not_of('h',  1 ) == size_type( 1 )    );
900     EXPECT_TRUE( sv.find_first_not_of('w'     ) == size_type( 0 )    );
901     EXPECT_TRUE( sv.find_first_not_of('w',  6 ) == size_type( 7 )    );
902     EXPECT_TRUE( sv.find_first_not_of('d', 10 ) == string_view::npos );
903 }
904
905 TEST(StringViewTest, CanSearchForFirstNonEqualToAnyCharacterInCStringInLength)
906 {
907     SCOPED_TRACE( "string_view: Allows to search for  the first character not equal to any of the characters specified in a C-string, starting at position pos and of length n via find_first_not_of(), (3)" );
908
909     char hello[] = "hello world";
910     string_view sv( hello );
911
912     EXPECT_TRUE( sv.find_first_not_of( hello, 0, sv.size() ) == string_view::npos );
913     EXPECT_TRUE( sv.find_first_not_of( hello, 3, sv.size() ) == string_view::npos );
914     EXPECT_TRUE( sv.find_first_not_of( "helo "  , 0, 5     ) == size_type(  6 ) );
915     EXPECT_TRUE( sv.find_first_not_of( "helo "  , 6, 5     ) == size_type(  6 ) );
916     EXPECT_TRUE( sv.find_first_not_of( "helo "  , 7, 5     ) == size_type(  8 ) );
917     EXPECT_TRUE( sv.find_first_not_of( "helo wr", 0, 7     ) == size_type( 10 ) );
918     EXPECT_TRUE( sv.find_first_not_of( "he"     , 0, 1     ) == size_type(  1 ) );
919 }
920
921 TEST(StringViewTest, CanSearchForFirstNonEqualToAnyCharacterInCString)
922 {
923     SCOPED_TRACE( "string_view: Allows to search for  the first character not equal to any of the characters specified in a C-string, starting at position pos via find_first_not_of(), (4)" );
924
925     char hello[] = "hello world";
926     string_view sv( hello );
927
928     EXPECT_TRUE( sv.find_first_not_of( hello    , 0 ) == string_view::npos );
929     EXPECT_TRUE( sv.find_first_not_of( hello    , 3 ) == string_view::npos );
930     EXPECT_TRUE( sv.find_first_not_of( "helo "  , 0 ) == size_type(  6 ) );
931     EXPECT_TRUE( sv.find_first_not_of( "helo "  , 6 ) == size_type(  6 ) );
932     EXPECT_TRUE( sv.find_first_not_of( "helo "  , 7 ) == size_type(  8 ) );
933     EXPECT_TRUE( sv.find_first_not_of( "helo wr", 0 ) == size_type( 10 ) );
934 }
935
936 TEST(StringViewTest, CanBackwardsSearchForForstNonFoundCharacterInView)
937 {
938     SCOPED_TRACE( "string_view: Allows to search backwards for the first character not specified in a string view, starting at position pos (default: npos) via find_last_not_of(), (1)" );
939
940     char hello[] = "hello world";
941     char empty[] = "";
942     string_view sv( hello );
943     string_view sve( empty );
944
945     EXPECT_TRUE( sv.find_last_not_of( sv    ) == string_view::npos );
946     EXPECT_TRUE( sv.find_last_not_of( sv, 3 ) == string_view::npos );
947     EXPECT_TRUE( sv.find_last_not_of( string_view("world " )    ) == size_type(  1 ) );
948     EXPECT_TRUE( sv.find_last_not_of( string_view("heo "   ), 4 ) == size_type(  3 ) );
949     EXPECT_TRUE( sv.find_last_not_of( string_view("heo "   ), 3 ) == size_type(  3 ) );
950     EXPECT_TRUE( sv.find_last_not_of( string_view("heo "   ), 2 ) == size_type(  2 ) );
951     EXPECT_TRUE( sv.find_last_not_of( string_view("x"      )    ) == size_type( 10 ) );
952
953     EXPECT_TRUE( sve.find_last_not_of( string_view("x") ) == string_view::npos );    // issue 20 (endless loop)
954 }
955
956 TEST(StringViewTest, CanBackwardsSearchForFirstNonMatchingCharacter)
957 {
958     SCOPED_TRACE( "string_view: Allows to search backwards for the first character not equal to the specified character, starting at position pos (default: npos) via find_last_not_of(), (2)" );
959
960     char hello[] = "hello world";
961     string_view sv( hello );
962
963     EXPECT_TRUE( sv.find_last_not_of('d'     ) == size_type( 9 ) );
964     EXPECT_TRUE( sv.find_last_not_of('d', 10 ) == size_type( 9 ) );
965     EXPECT_TRUE( sv.find_last_not_of('d',  9 ) == size_type( 9 ) );
966     EXPECT_TRUE( sv.find_last_not_of('d',  8 ) == size_type( 8 ) );
967     EXPECT_TRUE( sv.find_last_not_of('d',  0 ) == size_type( 0 ) );
968 }
969
970 TEST(StringViewTest, CanBackwardsSearchForFirstNonEqualToAnyCharacterInCStringInLength)
971 {
972     SCOPED_TRACE( "string_view: Allows to search backwards for  the first character not equal to any of the characters specified in a C-string, starting at position pos and of length n via find_last_not_of(), (3)" );
973
974     char hello[] = "hello world";
975     string_view sv( hello );
976
977     EXPECT_TRUE( sv.find_last_not_of( hello, 0, sv.size() ) == string_view::npos );
978     EXPECT_TRUE( sv.find_last_not_of( hello, 3, sv.size() ) == string_view::npos );
979     EXPECT_TRUE( sv.find_last_not_of( "world ", 10, 6 ) == size_type(  1 ) );
980     EXPECT_TRUE( sv.find_last_not_of( "heo "  ,  4, 4 ) == size_type(  3 ) );
981     EXPECT_TRUE( sv.find_last_not_of( "heo "  ,  3, 4 ) == size_type(  3 ) );
982     EXPECT_TRUE( sv.find_last_not_of( "heo "  ,  2, 4 ) == size_type(  2 ) );
983     EXPECT_TRUE( sv.find_last_not_of( "x"             ) == size_type( 10 ) );
984 }
985
986 TEST(StringViewTest, CanBackwardsSearchForFirstNonEqualToAnyCharacterInCString)
987 {
988     SCOPED_TRACE( "string_view: Allows to search backwards for  the first character not equal to any of the characters specified in a C-string, starting at position pos via find_last_not_of(), (4)" );
989
990     char hello[] = "hello world";
991     string_view sv( hello );
992
993     EXPECT_TRUE( sv.find_last_not_of( hello    , 0 ) == string_view::npos );
994     EXPECT_TRUE( sv.find_last_not_of( hello    , 3 ) == string_view::npos );
995     EXPECT_TRUE( sv.find_last_not_of( "world ", 10 ) == size_type(  1 ) );
996     EXPECT_TRUE( sv.find_last_not_of( "heo "  ,  4 ) == size_type(  3 ) );
997     EXPECT_TRUE( sv.find_last_not_of( "heo "  ,  3 ) == size_type(  3 ) );
998     EXPECT_TRUE( sv.find_last_not_of( "heo "  ,  2 ) == size_type(  2 ) );
999     EXPECT_TRUE( sv.find_last_not_of( "x"          ) == size_type( 10 ) );
1000 }
1001
1002 TEST(StringViewTest, CanCreateViewWithLiteralSV)
1003 {
1004     SCOPED_TRACE( "string_view: Allows to create a string_view, wstring_view, u16string_view, u32string_view via literal \"sv\"" );
1005
1006 #if nssv_CONFIG_STD_SV_OPERATOR
1007 #if nssv_STD_SV_OR( nssv_HAVE_STD_DEFINED_LITERALS )
1008     using namespace nonstd::literals::string_view_literals;
1009
1010     string_view sv1 =  "abc"sv;
1011     wstring_view sv2 = L"abc"sv;
1012
1013     EXPECT_TRUE( sv1.size() == size_type( 3 ) );
1014     EXPECT_TRUE( sv2.size() == size_type( 3 ) );
1015
1016 #if nssv_HAVE_WCHAR16_T
1017     u16string_view sv3 = u"abc"sv;
1018     EXPECT_TRUE( sv3.size() == size_type( 3 ) );
1019 #endif
1020 #if nssv_HAVE_WCHAR32_T
1021     u32string_view sv4 = U"abc"sv;
1022     EXPECT_TRUE( sv4.size() == size_type( 3 ) );
1023 #endif
1024 #else
1025     EXPECT_TRUE( !!"Literal operator 'sv' for string_view not available (no C++11)." );
1026 #endif
1027 #else
1028     EXPECT_TRUE( !!"Literal operator 'sv' for string_view not available (nssv_CONFIG_STD_SV_OPERATOR=0)." );
1029 #endif
1030 }
1031
1032 TEST(StringViewTest, CanCreateViewWithLiteralSVInLiteralsStringViewLiteralsNamespace)
1033 {
1034     SCOPED_TRACE( "string_view: Allows to create a string_view via literal \"sv\", using namespace gmx::compat::literals::string_view_literals" );
1035
1036 #if nssv_CONFIG_STD_SV_OPERATOR
1037 #if nssv_STD_SV_OR( nssv_HAVE_STD_DEFINED_LITERALS )
1038     using namespace gmx::compat::literals::string_view_literals;
1039
1040     string_view sv1 = "abc\0\0def";
1041     string_view sv2 = "abc\0\0def"sv;
1042
1043     EXPECT_TRUE( sv1.size() == size_type( 3 ) );
1044     EXPECT_TRUE( sv2.size() == size_type( 8 ) );
1045 #else
1046     EXPECT_TRUE( !!"Literal operator 'sv' for string_view not available (no C++11)." );
1047 #endif
1048 #else
1049     EXPECT_TRUE( !!"Literal operator 'sv' for string_view not available (nssv_CONFIG_STD_SV_OPERATOR=0)." );
1050 #endif
1051 }
1052
1053 TEST(StringViewTest, CanCreateViewWithLiteralSVInStringViewLiteralsNamespace)
1054 {
1055     SCOPED_TRACE( "string_view: Allows to create a string_view via literal \"sv\", using namespace gmx::compat::string_view_literals" );
1056
1057 #if nssv_CONFIG_STD_SV_OPERATOR
1058 #if nssv_STD_SV_OR( nssv_HAVE_STD_DEFINED_LITERALS )
1059 #if nssv_STD_SV_OR( nssv_HAVE_INLINE_NAMESPACE )
1060     using namespace gmx::compat::string_view_literals;
1061
1062     string_view sv1 = "abc\0\0def";
1063     string_view sv2 = "abc\0\0def"sv;
1064
1065     EXPECT_TRUE( sv1.size() == size_type( 3 ) );
1066     EXPECT_TRUE( sv2.size() == size_type( 8 ) );
1067 #else
1068     EXPECT_TRUE( !!"Inline namespaces for literal operator 'sv' for string_view not available (no C++11)." );
1069 #endif
1070 #else
1071     EXPECT_TRUE( !!"Literal operator 'sv' for string_view not available (no C++11)." );
1072 #endif
1073 #else
1074     EXPECT_TRUE( !!"Literal operator 'sv' for string_view not available (nssv_CONFIG_STD_SV_OPERATOR=0)." );
1075 #endif
1076 }
1077
1078 TEST(StringViewTest, CanCreateViewWithLiteralSVInLiteralsNamespace)
1079 {
1080     SCOPED_TRACE( "string_view: Allows to create a string_view via literal \"sv\", using namespace gmx::compat::literals" );
1081
1082 #if nssv_CONFIG_STD_SV_OPERATOR
1083 #if nssv_STD_SV_OR( nssv_HAVE_STD_DEFINED_LITERALS )
1084 #if nssv_STD_SV_OR( nssv_HAVE_INLINE_NAMESPACE )
1085     using namespace gmx::compat::literals;
1086
1087     string_view sv1 = "abc\0\0def";
1088     string_view sv2 = "abc\0\0def"sv;
1089
1090     EXPECT_TRUE( sv1.size() == size_type( 3 ) );
1091     EXPECT_TRUE( sv2.size() == size_type( 8 ) );
1092 #else
1093     EXPECT_TRUE( !!"Inline namespaces for literal operator 'sv' for string_view not available (no C++11)." );
1094 #endif
1095 #else
1096     EXPECT_TRUE( !!"Literal operator 'sv' for string_view not available (no C++11)." );
1097 #endif
1098 #else
1099     EXPECT_TRUE( !!"Literal operator 'sv' for string_view not available (nssv_CONFIG_STD_SV_OPERATOR=0)." );
1100 #endif
1101 }
1102
1103 TEST(StringViewTest, CanCreateViewWithLiteral_SV)
1104 {
1105     SCOPED_TRACE( "string_view: Allows to create a string_view, wstring_view, u16string_view, u32string_view via literal \"_sv\"" );
1106
1107 #if nssv_CONFIG_USR_SV_OPERATOR
1108 #if nssv_STD_SV_OR( nssv_HAVE_USER_DEFINED_LITERALS )
1109     using namespace gmx::compat::literals::string_view_literals;
1110
1111     string_view sv1 =  "abc"_sv;
1112     wstring_view sv2 = L"abc"_sv;
1113
1114     EXPECT_TRUE( sv1.size() == size_type( 3 ) );
1115     EXPECT_TRUE( sv2.size() == size_type( 3 ) );
1116
1117 #if nssv_HAVE_WCHAR16_T
1118     u16string_view sv3 = u"abc"_sv;
1119     EXPECT_TRUE( sv3.size() == size_type( 3 ) );
1120 #endif
1121 #if nssv_HAVE_WCHAR32_T
1122     u32string_view sv4 = U"abc"_sv;
1123     EXPECT_TRUE( sv4.size() == size_type( 3 ) );
1124 #endif
1125 #else
1126     EXPECT_TRUE( !!"Literal operator '_sv' for string_view not available (no C++11)." );
1127 #endif
1128 #else
1129     EXPECT_TRUE( !!"Literal operator '_sv' for string_view not available (nssv_CONFIG_USR_SV_OPERATOR=0)." );
1130 #endif
1131 }
1132
1133 TEST(StringViewTest, CanCreateViewWithLiteral_SVInLiteralsStringViewLiteralsNamespace)
1134 {
1135     SCOPED_TRACE( "string_view: Allows to create a string_view via literal \"_sv\", using namespace gmx::compat::literals::string_view_literals" );
1136
1137 #if nssv_CONFIG_USR_SV_OPERATOR
1138 #if nssv_STD_SV_OR( nssv_HAVE_USER_DEFINED_LITERALS )
1139     using namespace gmx::compat::literals::string_view_literals;
1140
1141     string_view sv1 = "abc\0\0def";
1142     string_view sv2 = "abc\0\0def"_sv;
1143
1144     EXPECT_TRUE( sv1.size() == size_type( 3 ) );
1145     EXPECT_TRUE( sv2.size() == size_type( 8 ) );
1146 #else
1147     EXPECT_TRUE( !!"Literal operator '_sv' for string_view not available (no C++11)." );
1148 #endif
1149 #else
1150     EXPECT_TRUE( !!"Literal operator '_sv' for string_view not available (nssv_CONFIG_USR_SV_OPERATOR=0)." );
1151 #endif
1152 }
1153
1154 TEST(StringViewTest, CanCreateViewWithLiteral_SVInStringViewLiteralsNamespace)
1155 {
1156     SCOPED_TRACE( "string_view: Allows to create a string_view via literal \"_sv\", using namespace gmx::compat::string_view_literals" );
1157
1158 #if nssv_CONFIG_USR_SV_OPERATOR
1159 #if nssv_STD_SV_OR( nssv_HAVE_USER_DEFINED_LITERALS )
1160 #if nssv_STD_SV_OR( nssv_HAVE_INLINE_NAMESPACE )
1161     using namespace gmx::compat::string_view_literals;
1162
1163     string_view sv1 = "abc\0\0def";
1164     string_view sv2 = "abc\0\0def"_sv;
1165
1166     EXPECT_TRUE( sv1.size() == size_type( 3 ) );
1167     EXPECT_TRUE( sv2.size() == size_type( 8 ) );
1168 #else
1169     EXPECT_TRUE( !!"Inline namespaces for literal operator '_sv' for string_view not available (no C++11)." );
1170 #endif
1171 #else
1172     EXPECT_TRUE( !!"Literal operator '_sv' for string_view not available (no C++11)." );
1173 #endif
1174 #else
1175     EXPECT_TRUE( !!"Literal operator '_sv' for string_view not available (nssv_CONFIG_USR_SV_OPERATOR=0)." );
1176 #endif
1177 }
1178
1179 TEST(StringViewTest, CanCreateViewWithLiteral_SVInLiteralsNamespace)
1180 {
1181     SCOPED_TRACE( "string_view: Allows to create a string_view via literal \"_sv\", using namespace gmx::compat::literals" );
1182
1183 #if nssv_CONFIG_USR_SV_OPERATOR
1184 #if nssv_STD_SV_OR( nssv_HAVE_USER_DEFINED_LITERALS )
1185 #if nssv_STD_SV_OR( nssv_HAVE_INLINE_NAMESPACE )
1186     using namespace gmx::compat::literals;
1187
1188     string_view sv1 = "abc\0\0def";
1189     string_view sv2 = "abc\0\0def"_sv;
1190
1191     EXPECT_TRUE( sv1.size() == size_type( 3 ) );
1192     EXPECT_TRUE( sv2.size() == size_type( 8 ) );
1193 #else
1194     EXPECT_TRUE( !!"Inline namespaces for literal operator '_sv' for string_view not available (no C++11)." );
1195 #endif
1196 #else
1197     EXPECT_TRUE( !!"Literal operator '_sv' for string_view not available (no C++11)." );
1198 #endif
1199 #else
1200     EXPECT_TRUE( !!"Literal operator '_sv' for string_view not available (nssv_CONFIG_USR_SV_OPERATOR=0)." );
1201 #endif
1202 }
1203
1204 // 24.4.3 Non-member comparison functions:
1205
1206 TEST(StringViewTest, CanCompareToViews)
1207 {
1208     SCOPED_TRACE( "string_view: Allows to compare a string_view with another string_view" );
1209
1210     char s[] = "hello";
1211     char t[] = "world";
1212     string_view sv( s );
1213     string_view tv( t );
1214
1215     EXPECT_TRUE( sv.length() == size_type( 5 ) );
1216     EXPECT_TRUE( tv.length() == size_type( 5 ) );
1217
1218     EXPECT_TRUE( sv == sv );
1219     EXPECT_TRUE( sv != tv );
1220     EXPECT_TRUE( sv <= sv );
1221     EXPECT_TRUE( sv <= tv );
1222     EXPECT_TRUE( sv <  tv );
1223     EXPECT_TRUE( tv >= tv );
1224     EXPECT_TRUE( tv >= sv );
1225     EXPECT_TRUE( tv >  sv );
1226 }
1227
1228 TEST(StringViewTest, CanCompareViewToImplicitlyConvertedView)
1229 {
1230     SCOPED_TRACE( "string_view: Allows to compare a string_view with an object with implicit conversion to string_view" );
1231
1232 #if nssv_CPP11_OR_GREATER
1233 #if defined(_MSC_VER) && _MSC_VER != 1900
1234     char s[] = "hello";
1235     string_view sv( s );
1236
1237     EXPECT_TRUE( sv == "hello"       );
1238     EXPECT_TRUE(       "hello" == sv );
1239
1240     EXPECT_TRUE( sv != "world"       );
1241     EXPECT_TRUE(       "world" != sv );
1242
1243     EXPECT_TRUE( sv <= "hello"       );
1244     EXPECT_TRUE(       "hello" <= sv );
1245     EXPECT_TRUE( sv <= "world"       );
1246     EXPECT_TRUE(       "aloha" <= sv );
1247
1248     EXPECT_TRUE( sv <  "world"       );
1249     EXPECT_TRUE(       "aloha" <  sv );
1250
1251     EXPECT_TRUE( sv >= "hello"       );
1252     EXPECT_TRUE(       "hello" >= sv );
1253     EXPECT_TRUE( sv >= "aloha"       );
1254     EXPECT_TRUE(       "world" >= sv );
1255
1256     EXPECT_TRUE( sv >  "aloha"       );
1257     EXPECT_TRUE(       "world"  >  sv );
1258 #else
1259     EXPECT_TRUE( !!"Comparison for types with implicit conversion to string_view not available (insufficient C++11 support of MSVC)." );
1260 #endif
1261 #else
1262     EXPECT_TRUE( !!"Comparison for types with implicit conversion to string_view not available (no C++11)." );
1263 #endif
1264 }
1265
1266 TEST(StringViewTest, EmptyViewsCompareAsEqual)
1267 {
1268     SCOPED_TRACE( "string_view: Allows to compare empty string_view-s as equal" );
1269
1270     string_view a, b;
1271
1272     EXPECT_TRUE( a == b );
1273 }
1274
1275 // 24.4.4 Inserters and extractors:
1276
1277 TEST(StringViewTest, CanPrintViewToPutputStream)
1278 {
1279     SCOPED_TRACE ( "operator<<: Allows printing a string_view to an output stream" );
1280
1281     std::ostringstream oss;
1282     char s[] = "hello";
1283     string_view sv( s );
1284
1285     oss << sv << '\n'
1286         << std::right << std::setw(10) << sv << '\n'
1287         << sv << '\n'
1288         << std::setfill('.') << std::left << std::setw(10) << sv;
1289
1290     EXPECT_TRUE( oss.str() == "hello\n     hello\nhello\nhello....." );
1291 }
1292
1293 // 24.4.5 Hash support (C++11):
1294
1295 TEST(StringViewTest, HashOfViewIsEqualToHashOfString)
1296 {
1297     SCOPED_TRACE ( "std::hash<>: Hash value of string_view equals hash value of corresponding string object" );
1298
1299 #if nssv_HAVE_STD_HASH
1300     EXPECT_TRUE( std::hash<string_view>()( "Hello, world!" ) == std::hash<std::string>()( "Hello, world!" ) );
1301 #else
1302     EXPECT_TRUE( !!"std::hash is not available (no C++11)" );
1303 #endif
1304 }
1305
1306 TEST(StringViewTest, HashOfWStringViewIsEqualToHashOfString)
1307 {
1308     SCOPED_TRACE ( "std::hash<>: Hash value of wstring_view equals hash value of corresponding string object" );
1309
1310 #if nssv_HAVE_STD_HASH
1311     EXPECT_TRUE( std::hash<wstring_view>()( L"Hello, world!" ) == std::hash<std::wstring>()( L"Hello, world!" ) );
1312 #else
1313     EXPECT_TRUE( !!"std::hash is not available (no C++11)" );
1314 #endif
1315 }
1316
1317 TEST(StringViewTest, HashOfU16StringViewIsEqualToHashOfString)
1318 {
1319     SCOPED_TRACE ( "std::hash<>: Hash value of u16string_view equals hash value of corresponding string object" );
1320
1321 #if nssv_HAVE_STD_HASH
1322 #if nssv_HAVE_WCHAR16_T
1323 #if nssv_HAVE_UNICODE_LITERALS
1324     EXPECT_TRUE( std::hash<u16string_view>()( u"Hello, world!" ) == std::hash<std::u16string>()( u"Hello, world!" ) );
1325 #else
1326     EXPECT_TRUE( !!"Unicode literal u\"...\" is not available (no C++11)" );
1327 #endif
1328 #else
1329     EXPECT_TRUE( !!"std::u16string is not available (no C++11)" );
1330 #endif
1331 #else
1332     EXPECT_TRUE( !!"std::hash is not available (no C++11)" );
1333 #endif
1334 }
1335
1336 TEST(StringViewTest, HashOfU32StringViewIsEqualToHashOfString)
1337 {
1338     SCOPED_TRACE ( "std::hash<>: Hash value of u32string_view equals hash value of corresponding string object" );
1339
1340 #if nssv_HAVE_STD_HASH
1341 #if nssv_HAVE_WCHAR16_T
1342 #if nssv_HAVE_UNICODE_LITERALS
1343     EXPECT_TRUE( std::hash<u32string_view>()( U"Hello, world!" ) == std::hash<std::u32string>()( U"Hello, world!" ) );
1344 #else
1345     EXPECT_TRUE( !!"Unicode literal U\"...\" is not available (no C++11)" );
1346 #endif
1347 #else
1348     EXPECT_TRUE( !!"std::u32string is not available (no C++11)" );
1349 #endif
1350 #else
1351     EXPECT_TRUE( !!"std::hash is not available (no C++11)" );
1352 #endif
1353 }
1354
1355 // nonstd extension: conversions from and to std::basic_string
1356
1357 TEST(StringViewExtensionTest, CanConstructViewFromString)
1358 {
1359     SCOPED_TRACE( "string_view: construct from std::string " "[extension]" );
1360
1361 #if nssv_USES_STD_STRING_VIEW
1362     EXPECT_TRUE( !!"Conversion to/from std::string is not available (nssv_USES_STD_STRING_VIEW=1)." );
1363 #elif nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS
1364     char hello[]  = "hello world";
1365     std::string s =  hello;
1366
1367     string_view sv( hello );
1368
1369     EXPECT_TRUE( sv.size() == s.size() );
1370     EXPECT_TRUE( sv.compare( s ) == 0  );
1371 #else
1372     EXPECT_TRUE( !!"Conversion to/from std::string is not available (nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS=0)." );
1373 #endif
1374 }
1375
1376 TEST(StringViewExtensionTest, CanConvertViewToStringViaExplicitOperator)
1377 {
1378     SCOPED_TRACE( "string_view: convert to std::string via explicit operator " "[extension]" );
1379
1380 #if nssv_USES_STD_STRING_VIEW
1381     EXPECT_TRUE( !!"Conversion to/from std::string is not available (nssv_USES_STD_STRING_VIEW=1)." );
1382 #elif nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS
1383 #if nssv_HAVE_EXPLICIT_CONVERSION
1384     char hello[] = "hello world";
1385     string_view sv( hello );
1386
1387     std::string s( sv );
1388 //  std::string t{ sv };
1389
1390     EXPECT_TRUE( sv.size() == s.size() );
1391     EXPECT_TRUE( sv.compare( s ) == 0  );
1392 #else
1393     EXPECT_TRUE( !!"explicit conversion is not available (no C++11)." );
1394 #endif
1395 #else
1396     EXPECT_TRUE( !!"Conversion to/from std::string is not available (nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS=0)." );
1397 #endif
1398 }
1399
1400 TEST(StringViewExtensionTest, CanConvertViewToStringViaToString)
1401 {
1402     SCOPED_TRACE( "string_view: convert to std::string via to_string() " "[extension]" );
1403
1404 #if nssv_USES_STD_STRING_VIEW
1405     EXPECT_TRUE( !!"Conversion to/from std::string is not available (nssv_USES_STD_STRING_VIEW=1)." );
1406 #elif nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS
1407     char hello[] = "hello world";
1408     string_view sv( hello );
1409
1410     std::string s1 = sv.to_string();
1411
1412     EXPECT_TRUE( sv.size() == s1.size() );
1413     EXPECT_TRUE( sv.compare( s1 ) == 0  );
1414
1415     std::string s2 = sv.to_string( std::string::allocator_type() );
1416
1417     EXPECT_TRUE( sv.size() == s2.size() );
1418     EXPECT_TRUE( sv.compare( s2 ) == 0  );
1419 #else
1420     EXPECT_TRUE( !!"Conversion to/from std::string is not available (nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS=0)." );
1421 #endif
1422 }
1423
1424 TEST(StringViewExtensionTest, CanConvertViewToStringViaToStringFreeFunction)
1425 {
1426     SCOPED_TRACE( "to_string(): convert to std::string via to_string() " "[extension]" );
1427
1428 #if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
1429     char hello[] = "hello world";
1430     string_view sv( hello );
1431
1432     std::string s1 = to_string( sv );
1433
1434     EXPECT_TRUE( sv.size() == s1.size() );
1435     EXPECT_TRUE( sv.compare( s1 ) == 0  );
1436
1437     std::string s2 = to_string( sv, std::string::allocator_type() );
1438
1439     EXPECT_TRUE( sv.size() == s2.size() );
1440     EXPECT_TRUE( sv.compare( s2 ) == 0  );
1441
1442 #else
1443     EXPECT_TRUE( !!"Conversion to/from std::string is not available (nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS=0)." );
1444 #endif
1445 }
1446
1447 TEST(StringViewExtensionTest, CanConvertViewToStringViewViaToStringView)
1448 {
1449     SCOPED_TRACE( "to_string_view(): convert from std::string via to_string_view() " "[extension]" );
1450
1451 #if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS
1452     char hello[] = "hello world";
1453     std::string s = hello;
1454
1455     string_view sv = to_string_view( s );
1456
1457     EXPECT_TRUE( sv.size() == s.size() );
1458     EXPECT_TRUE( sv.compare( s ) == 0  );
1459 #else
1460     EXPECT_TRUE( !!"Conversion to/from std::string is not available (nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS=0)." );
1461 #endif
1462 }
1463
1464 } // anonymous namespace
1465
1466 } // namespace gmx
1467
1468 // GMX modification to suppress Doxygen checking
1469 #endif // DOXYGEN