1//////////////////////////////////////////////////////////////////////////////
2//
3// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost
4// Software License, Version 1.0. (See accompanying file
5// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7// See http://www.boost.org/libs/container for documentation.
8//
9//////////////////////////////////////////////////////////////////////////////
10
11#include <boost/container/vector.hpp>
12#include <boost/container/string.hpp>
13#include <string>
14#include <vector>
15#include <boost/container/detail/algorithm.hpp> //equal()
16#include <cstring>
17#include <cstdio>
18#include <cstddef>
19#include <new>
20#include "dummy_test_allocator.hpp"
21#include "check_equal_containers.hpp"
22#include "expand_bwd_test_allocator.hpp"
23#include "expand_bwd_test_template.hpp"
24#include "propagate_allocator_test.hpp"
25#include "default_init_test.hpp"
26#include "comparison_test.hpp"
27#include "../../intrusive/test/iterator_test.hpp"
28#include <boost/utility/string_view.hpp>
29#include <boost/core/lightweight_test.hpp>
30
31using namespace boost::container;
32
33struct StringEqual
34{
35 template<class Str1, class Str2>
36 bool operator ()(const Str1 &string1, const Str2 &string2) const
37 {
38 if(string1.size() != string2.size())
39 return false;
40 return std::char_traits<typename Str1::value_type>::compare
41 (string1.c_str(), string2.c_str(), string1.size()) == 0;
42 }
43};
44
45//Function to check if both lists are equal
46template<class StrVector1, class StrVector2>
47bool CheckEqualStringVector(StrVector1 *strvect1, StrVector2 *strvect2)
48{
49 StringEqual comp;
50 return boost::container::algo_equal(strvect1->begin(), strvect1->end(),
51 strvect2->begin(), comp);
52}
53
54template<class ForwardIt>
55ForwardIt unique(ForwardIt first, ForwardIt const last)
56{
57 if(first == last){
58 ForwardIt i = first;
59 //Find first adjacent pair
60 while(1){
61 if(++i == last){
62 return last;
63 }
64 else if(*first == *i){
65 break;
66 }
67 ++first;
68 }
69 //Now overwrite skipping adjacent elements
70 while (++i != last) {
71 if (!(*first == *i)) {
72 *(++first) = boost::move(*i);
73 }
74 }
75 ++first;
76 }
77 return first;
78}
79
80template<class CharType>
81struct string_literals;
82
83template<>
84struct string_literals<char>
85{
86 static const char *String()
87 { return "String"; }
88 static const char *Prefix()
89 { return "Prefix"; }
90 static const char *Suffix()
91 { return "Suffix"; }
92 static const char *LongString()
93 { return "LongLongLongLongLongLongLongLongLongLongLongLongLongString"; }
94 static char Char()
95 { return 'C'; }
96 static void sprintf_number(char *buf, int number)
97 {
98 std::sprintf(s: buf, format: "%i", number);
99 }
100 static void sprintf_number(char *buf, unsigned number)
101 {
102 std::sprintf(s: buf, format: "%u", number);
103 }
104 static void sprintf_number(char *buf, long number)
105 {
106 std::sprintf(s: buf, format: "%li", number);
107 }
108 static void sprintf_number(char *buf, unsigned long number)
109 {
110 std::sprintf(s: buf, format: "%lu", number);
111 }
112 static void sprintf_number(char *buf, long long number)
113 {
114 std::sprintf(s: buf, format: "%lli", number);
115 }
116 static void sprintf_number(char *buf, unsigned long long number)
117 {
118 std::sprintf(s: buf, format: "%llu", number);
119 }
120};
121
122template<>
123struct string_literals<wchar_t>
124{
125 static const wchar_t *String()
126 { return L"String"; }
127 static const wchar_t *Prefix()
128 { return L"Prefix"; }
129 static const wchar_t *Suffix()
130 { return L"Suffix"; }
131 static const wchar_t *LongString()
132 { return L"LongLongLongLongLongLongLongLongLongLongLongLongLongString"; }
133 static wchar_t Char()
134 { return L'C'; }
135 static void sprintf_number(wchar_t *buffer, unsigned long long number)
136 {
137 //For compilers without wsprintf, print it backwards
138 const wchar_t *digits = L"0123456789";
139 wchar_t *buf = buffer;
140
141 while(1){
142 unsigned long long rem = number % 10;
143 number = number / 10;
144
145 *buf = digits[rem];
146 ++buf;
147 if(!number){
148 *buf = 0;
149 break;
150 }
151 }
152
153 }
154};
155
156template<class CharType>
157int string_test()
158{
159 typedef std::basic_string<CharType> StdString;
160 typedef vector<StdString> StdStringVector;
161 typedef basic_string<CharType> BoostString;
162 typedef vector<BoostString> BoostStringVector;
163
164 const std::size_t MaxSize = 100;
165
166 {
167 BoostStringVector *boostStringVect = new BoostStringVector;
168 StdStringVector *stdStringVect = new StdStringVector;
169 BoostString auxBoostString;
170 StdString auxStdString(StdString(auxBoostString.begin(), auxBoostString.end() ));
171
172 CharType buffer [20];
173
174 //First, push back
175 for(std::size_t i = 0; i < MaxSize; ++i){
176 auxBoostString = string_literals<CharType>::String();
177 auxStdString = string_literals<CharType>::String();
178 string_literals<CharType>::sprintf_number(buffer, i);
179 auxBoostString += buffer;
180 auxStdString += buffer;
181 boostStringVect->push_back(auxBoostString);
182 stdStringVect->push_back(auxStdString);
183 }
184
185 if(auxBoostString.data() != const_cast<const BoostString&>(auxBoostString).data() &&
186 auxBoostString.data() != &auxBoostString[0])
187 return 1;
188
189 if(!CheckEqualStringVector(boostStringVect, stdStringVect)){
190 return 1;
191 }
192
193 //Now push back moving
194 for(std::size_t i = 0; i < MaxSize; ++i){
195 auxBoostString = string_literals<CharType>::String();
196 auxStdString = string_literals<CharType>::String();
197 string_literals<CharType>::sprintf_number(buffer, i);
198 auxBoostString += buffer;
199 auxStdString += buffer;
200 boostStringVect->push_back(boost::move(auxBoostString));
201 stdStringVect->push_back(auxStdString);
202 }
203
204 if(!CheckEqualStringVector(boostStringVect, stdStringVect)){
205 return 1;
206 }
207
208 //push front
209 for(std::size_t i = 0; i < MaxSize; ++i){
210 auxBoostString = string_literals<CharType>::String();
211 auxStdString = string_literals<CharType>::String();
212 string_literals<CharType>::sprintf_number(buffer, i);
213 auxBoostString += buffer;
214 auxStdString += buffer;
215 boostStringVect->insert(boostStringVect->begin(), auxBoostString);
216 stdStringVect->insert(stdStringVect->begin(), auxStdString);
217 }
218
219 if(!CheckEqualStringVector(boostStringVect, stdStringVect)){
220 return 1;
221 }
222
223 //Now push front moving
224 for(std::size_t i = 0; i < MaxSize; ++i){
225 auxBoostString = string_literals<CharType>::String();
226 auxStdString = string_literals<CharType>::String();
227 string_literals<CharType>::sprintf_number(buffer, i);
228 auxBoostString += buffer;
229 auxStdString += buffer;
230 boostStringVect->insert(boostStringVect->begin(), boost::move(auxBoostString));
231 stdStringVect->insert(stdStringVect->begin(), auxStdString);
232 }
233
234 if(!CheckEqualStringVector(boostStringVect, stdStringVect)){
235 return 1;
236 }
237
238 //Now test long and short representation swapping
239
240 //Short first
241 auxBoostString = string_literals<CharType>::String();
242 auxStdString = string_literals<CharType>::String();
243 BoostString boost_swapper;
244 StdString std_swapper;
245 boost_swapper.swap(auxBoostString);
246 std_swapper.swap(auxStdString);
247 if(!StringEqual()(auxBoostString, auxStdString))
248 return 1;
249 if(!StringEqual()(boost_swapper, std_swapper))
250 return 1;
251 boost_swapper.swap(auxBoostString);
252 std_swapper.swap(auxStdString);
253 if(!StringEqual()(auxBoostString, auxStdString))
254 return 1;
255 if(!StringEqual()(boost_swapper, std_swapper))
256 return 1;
257
258 //Shrink_to_fit
259 auxBoostString.shrink_to_fit();
260 StdString(auxStdString).swap(auxStdString);
261 if(!StringEqual()(auxBoostString, auxStdString))
262 return 1;
263
264 //Reserve + shrink_to_fit
265 auxBoostString.reserve(boost_swapper.size()*2+1);
266 auxStdString.reserve(std_swapper.size()*2+1);
267 if(!StringEqual()(auxBoostString, auxStdString))
268 return 1;
269
270 auxBoostString.shrink_to_fit();
271 StdString(auxStdString).swap(auxStdString);
272 if(!StringEqual()(auxBoostString, auxStdString))
273 return 1;
274
275 //Long string
276 auxBoostString = string_literals<CharType>::LongString();
277 auxStdString = string_literals<CharType>::LongString();
278 boost_swapper = BoostString();
279 std_swapper = StdString();
280 boost_swapper.swap(auxBoostString);
281 std_swapper.swap(auxStdString);
282 if(!StringEqual()(auxBoostString, auxStdString))
283 return 1;
284 if(!StringEqual()(boost_swapper, std_swapper))
285 return 1;
286 boost_swapper.swap(auxBoostString);
287 std_swapper.swap(auxStdString);
288
289 //Shrink_to_fit
290 auxBoostString.shrink_to_fit();
291 StdString(auxStdString).swap(auxStdString);
292 if(!StringEqual()(auxBoostString, auxStdString))
293 return 1;
294
295 auxBoostString.clear();
296 auxStdString.clear();
297 auxBoostString.shrink_to_fit();
298 StdString(auxStdString).swap(auxStdString);
299 if(!StringEqual()(auxBoostString, auxStdString))
300 return 1;
301
302 //No sort
303 std::sort(boostStringVect->begin(), boostStringVect->end());
304 std::sort(stdStringVect->begin(), stdStringVect->end());
305 if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
306
307 const CharType *prefix = string_literals<CharType>::Prefix();
308 const std::size_t prefix_size = std::char_traits<CharType>::length(prefix);
309 const CharType *sufix = string_literals<CharType>::Suffix();
310
311 for(std::size_t i = 0; i < MaxSize; ++i){
312 (*boostStringVect)[i].append(sufix);
313 (*stdStringVect)[i].append(sufix);
314 (*boostStringVect)[i].insert((*boostStringVect)[i].begin(),
315 prefix, prefix + prefix_size);
316 (*stdStringVect)[i].insert((*stdStringVect)[i].begin(),
317 prefix, prefix + prefix_size);
318 }
319
320 if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
321
322 for(std::size_t i = 0; i < MaxSize; ++i){
323 std::reverse((*boostStringVect)[i].begin(), (*boostStringVect)[i].end());
324 std::reverse((*stdStringVect)[i].begin(), (*stdStringVect)[i].end());
325 }
326
327 if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
328
329 for(std::size_t i = 0; i < MaxSize; ++i){
330 std::reverse((*boostStringVect)[i].begin(), (*boostStringVect)[i].end());
331 std::reverse((*stdStringVect)[i].begin(), (*stdStringVect)[i].end());
332 }
333
334 if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
335
336 for(std::size_t i = 0; i < MaxSize; ++i){
337 std::sort(boostStringVect->begin(), boostStringVect->end());
338 std::sort(stdStringVect->begin(), stdStringVect->end());
339 }
340
341 if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
342
343 for(std::size_t i = 0; i < MaxSize; ++i){
344 (*boostStringVect)[i].replace((*boostStringVect)[i].begin(),
345 (*boostStringVect)[i].end(),
346 string_literals<CharType>::String());
347 (*stdStringVect)[i].replace((*stdStringVect)[i].begin(),
348 (*stdStringVect)[i].end(),
349 string_literals<CharType>::String());
350 }
351
352 if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
353
354 boostStringVect->erase(::unique(boostStringVect->begin(), boostStringVect->end()),
355 boostStringVect->end());
356 stdStringVect->erase(::unique(stdStringVect->begin(), stdStringVect->end()),
357 stdStringVect->end());
358 if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
359
360 //Check addition
361 {
362 BoostString bs2 = string_literals<CharType>::String();
363 StdString ss2 = string_literals<CharType>::String();
364 BoostString bs3 = string_literals<CharType>::Suffix();
365 StdString ss3 = string_literals<CharType>::Suffix();
366 BoostString bs4 = bs2 + bs3;
367 StdString ss4 = ss2 + ss3;
368 if(!StringEqual()(bs4, ss4)){
369 return 1;
370 }
371
372 bs4 = bs2 + BoostString();
373 ss4 = ss2 + StdString();
374 if(!StringEqual()(bs4, ss4)){
375 return 1;
376 }
377
378 bs4 = BoostString() + bs2;
379 ss4 = StdString() + ss2;
380 if(!StringEqual()(bs4, ss4)){
381 return 1;
382 }
383
384 bs4 = BoostString() + boost::move(bs2);
385 ss4 = StdString() + boost::move(ss2);
386 if(!StringEqual()(bs4, ss4)){
387 return 1;
388 }
389
390 bs2 = string_literals<CharType>::String();
391 ss2 = string_literals<CharType>::String();
392 bs4 = boost::move(bs2) + BoostString();
393 ss4 = boost::move(ss2) + StdString();
394 if(!StringEqual()(bs4, ss4)){
395 return 1;
396 }
397
398 bs2 = string_literals<CharType>::String();
399 ss2 = string_literals<CharType>::String();
400 bs4 = string_literals<CharType>::Prefix() + boost::move(bs2);
401 ss4 = string_literals<CharType>::Prefix() + boost::move(ss2);
402 if(!StringEqual()(bs4, ss4)){
403 return 1;
404 }
405
406 bs2 = string_literals<CharType>::String();
407 ss2 = string_literals<CharType>::String();
408 bs4 = boost::move(bs2) + string_literals<CharType>::Suffix();
409 ss4 = boost::move(ss2) + string_literals<CharType>::Suffix();
410 if(!StringEqual()(bs4, ss4)){
411 return 1;
412 }
413
414 bs2 = string_literals<CharType>::String();
415 ss2 = string_literals<CharType>::String();
416 bs4 = string_literals<CharType>::Prefix() + bs2;
417 ss4 = string_literals<CharType>::Prefix() + ss2;
418 if(!StringEqual()(bs4, ss4)){
419 return 1;
420 }
421
422 bs2 = string_literals<CharType>::String();
423 ss2 = string_literals<CharType>::String();
424 bs4 = bs2 + string_literals<CharType>::Suffix();
425 ss4 = ss2 + string_literals<CharType>::Suffix();
426 if(!StringEqual()(bs4, ss4)){
427 return 1;
428 }
429
430 bs2 = string_literals<CharType>::String();
431 ss2 = string_literals<CharType>::String();
432 bs4 = string_literals<CharType>::Char() + bs2;
433 ss4 = string_literals<CharType>::Char() + ss2;
434 if(!StringEqual()(bs4, ss4)){
435 return 1;
436 }
437
438 bs2 = string_literals<CharType>::String();
439 ss2 = string_literals<CharType>::String();
440 bs4 = bs2 + string_literals<CharType>::Char();
441 ss4 = ss2 + string_literals<CharType>::Char();
442 if(!StringEqual()(bs4, ss4)){
443 return 1;
444 }
445
446 //Check front/back/begin/end
447
448 if(bs4.front() != *ss4.begin())
449 return 1;
450
451 if(bs4.back() != *(ss4.end()-1))
452 return 1;
453
454 bs4.pop_back();
455 ss4.erase(ss4.end()-1);
456 if(!StringEqual()(bs4, ss4)){
457 return 1;
458 }
459
460 if(*bs4.begin() != *ss4.begin())
461 return 1;
462 if(*bs4.cbegin() != *ss4.begin())
463 return 1;
464 if(*bs4.rbegin() != *ss4.rbegin())
465 return 1;
466 if(*bs4.crbegin() != *ss4.rbegin())
467 return 1;
468 if(*(bs4.end()-1) != *(ss4.end()-1))
469 return 1;
470 if(*(bs4.cend()-1) != *(ss4.end()-1))
471 return 1;
472 if(*(bs4.rend()-1) != *(ss4.rend()-1))
473 return 1;
474 if(*(bs4.crend()-1) != *(ss4.rend()-1))
475 return 1;
476 }
477
478#ifndef BOOST_CONTAINER_NO_CXX17_CTAD
479 //Chect Constructor Template Auto Deduction
480 {
481 auto gold = StdString(string_literals<CharType>::String());
482 auto test = basic_string(gold.begin(), gold.end());
483 if(!StringEqual()(gold, test)) {
484 return 1;
485 }
486 }
487#endif
488
489
490 //When done, delete vector
491 delete boostStringVect;
492 delete stdStringVect;
493 }
494 return 0;
495}
496
497bool test_expand_bwd()
498{
499 //Now test all back insertion possibilities
500 typedef test::expand_bwd_test_allocator<char>
501 allocator_type;
502 typedef basic_string<char, std::char_traits<char>, allocator_type>
503 string_type;
504 return test::test_all_expand_bwd<string_type>();
505}
506
507struct boost_container_string;
508
509namespace boost { namespace container { namespace test {
510
511template<>
512struct alloc_propagate_base<boost_container_string>
513{
514 template <class T, class Allocator>
515 struct apply
516 {
517 typedef boost::container::basic_string<T, std::char_traits<T>, Allocator> type;
518 };
519};
520
521
522}}} //namespace boost::container::test
523
524
525int main()
526{
527 {
528 boost::container::string a = "abcdefghijklmnopqrstuvwxyz";
529 boost::container::hash_value(v: a);
530 }
531
532
533 if(string_test<char>()){
534 return 1;
535 }
536
537 if(string_test<wchar_t>()){
538 return 1;
539 }
540
541 ////////////////////////////////////
542 // Backwards expansion test
543 ////////////////////////////////////
544 if(!test_expand_bwd())
545 return 1;
546
547 ////////////////////////////////////
548 // Allocator propagation testing
549 ////////////////////////////////////
550 if(!boost::container::test::test_propagate_allocator<boost_container_string>())
551 return 1;
552
553 ////////////////////////////////////
554 // Default init test
555 ////////////////////////////////////
556 if(!test::default_init_test< basic_string<char, std::char_traits<char>, test::default_init_allocator<char> > >()){
557 std::cerr << "Default init test failed" << std::endl;
558 return 1;
559 }
560
561 if(!test::default_init_test< basic_string<wchar_t, std::char_traits<wchar_t>, test::default_init_allocator<wchar_t> > >()){
562 std::cerr << "Default init test failed" << std::endl;
563 return 1;
564 }
565
566 ////////////////////////////////////
567 // Iterator testing
568 ////////////////////////////////////
569 {
570 typedef boost::container::basic_string<char> cont_int;
571 cont_int a; a.push_back(c: char(1)); a.push_back(c: char(2)); a.push_back(c: char(3));
572 boost::intrusive::test::test_iterator_random< cont_int >(c&: a);
573 }
574 {
575 typedef boost::container::basic_string<wchar_t> cont_int;
576 cont_int a; a.push_back(c: wchar_t(1)); a.push_back(c: wchar_t(2)); a.push_back(c: wchar_t(3));
577 boost::intrusive::test::test_iterator_random< cont_int >(c&: a);
578 }
579
580 ////////////////////////////////////
581 // Comparison testing
582 ////////////////////////////////////
583 {
584 if(!boost::container::test::test_container_comparisons<string>())
585 return 1;
586 if(!boost::container::test::test_container_comparisons<wstring>())
587 return 1;
588 }
589
590 ////////////////////////////////////
591 // has_trivial_destructor_after_move testing
592 ////////////////////////////////////
593 // default allocator
594 {
595 typedef boost::container::basic_string<char> cont;
596 typedef cont::allocator_type allocator_type;
597 typedef boost::container::allocator_traits<allocator_type>::pointer pointer;
598 BOOST_CONTAINER_STATIC_ASSERT_MSG
599 ( (boost::has_trivial_destructor_after_move<cont>::value ==
600 (boost::has_trivial_destructor_after_move<allocator_type>::value &&
601 boost::has_trivial_destructor_after_move<pointer>::value)),
602 "has_trivial_destructor_after_move(default allocator) test failed");
603 }
604 // std::allocator
605 {
606 typedef boost::container::basic_string<char, std::char_traits<char>, std::allocator<char> > cont;
607 typedef cont::allocator_type allocator_type;
608 typedef boost::container::allocator_traits<allocator_type>::pointer pointer;
609 BOOST_CONTAINER_STATIC_ASSERT_MSG
610 ( (boost::has_trivial_destructor_after_move<cont>::value ==
611 (boost::has_trivial_destructor_after_move<allocator_type>::value &&
612 boost::has_trivial_destructor_after_move<pointer>::value)),
613 "has_trivial_destructor_after_move(std::allocator) test failed");
614 }
615
616 return boost::report_errors();
617}
618

source code of boost/libs/container/test/string_test.cpp