add folly::FixedString, a constexpr-usable string with a fixed-size internal buffer
[folly.git] / folly / test / FixedStringTest.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 //
18 // Author: eniebler@fb.com
19
20 #include <folly/FixedString.h>
21 #include <folly/portability/GTest.h>
22
23 #define FS(x) ::folly::makeFixedString(x)
24 using namespace folly::StringLiterals;
25
26 TEST(FixedStringExamples, Examples) {
27   // Example from the docs:
28   using namespace folly;
29   constexpr auto hello = makeFixedString("hello"); // a FixedString<5>
30   constexpr auto world = makeFixedString("world"); // another FixedString<5>
31   constexpr auto hello_world = hello + ' ' + world + '!';
32   static_assert(hello_world == "hello world!", "w00t");
33   EXPECT_STREQ("hello world!", hello_world.c_str());
34
35   FixedString<10> test{"****"};
36   test.replace(1, 2, "!!!!");
37   EXPECT_STREQ("*!!!!*", test.c_str());
38   static_assert(makeFixedString("****").creplace(1, 2, "!!!!") == "*!!!!*", "");
39 }
40
41 TEST(FixedStringCtorTest, Default) {
42   constexpr folly::FixedString<42> s{};
43   static_assert(s[0] == '\0', "");
44   static_assert(s.size() == 0u, "");
45
46   constexpr auto s2 = s;
47   static_assert(s2[0] == '\0', "");
48   static_assert(s2.size() == 0u, "");
49 }
50
51 TEST(FixedStringCtorTest, FromLiterals) {
52   constexpr folly::FixedString<42> s{"hello world"};
53   constexpr folly::FixedString<11> s2{"hello world"};
54   static_assert(s2[0] == 'h', "");
55   static_assert(s2[10] == 'd', "");
56   static_assert(s2[11] == '\0', "");
57
58   // Does not compile, hurray! :-)
59   // constexpr char a[1] = {'a'};
60   // constexpr folly::FixedString<10> s3(a);
61 }
62
63 TEST(FixedStringCtorTest, FromPtrAndLength) {
64   constexpr folly::FixedString<11> s{"hello world", 11};
65   static_assert(s[0] == 'h', "");
66   static_assert(s[10] == 'd', "");
67   static_assert(s[11] == '\0', "");
68   static_assert(s.size() == 11u, "");
69
70   constexpr folly::FixedString<5> s2{"hello world", 5};
71   static_assert(s2[0] == 'h', "");
72   static_assert(s2[4] == 'o', "");
73   static_assert(s2[5] == '\0', "");
74   static_assert(s2.size() == 5u, "");
75
76   constexpr folly::FixedString<20> s3{"hello world", 5};
77   static_assert(s2[0] == 'h', "");
78   static_assert(s2[4] == 'o', "");
79   static_assert(s2[5] == '\0', "");
80   static_assert(s2.size() == 5u, "");
81
82   static_assert("hello" == s3, "");
83   static_assert(s3 == "hello", "");
84   static_assert(s3 == s2, "");
85   static_assert("hell" != s3, "");
86   static_assert(s3 != "helloooo", "");
87   static_assert(!(s3 != s2), "");
88 }
89
90 TEST(FixedStringCtorTest, FromStringAndOffset) {
91   constexpr folly::FixedString<11> s{"hello world"};
92   constexpr folly::FixedString<5> s2{s, 6u, npos};
93   static_assert(s2 == "world", "");
94   constexpr folly::FixedString<0> s3{s, 11u, npos};
95   static_assert(s3 == "", "");
96   // Out of bounds offset, does not compile
97   // constexpr folly::FixedString<0> s4{s, 12};
98 }
99
100 TEST(FixedStringCtorTest, FromStringOffsetAndCount) {
101   constexpr folly::FixedString<11> s{"hello world"};
102   constexpr folly::FixedString<4> s2{s, 6u, 4u};
103   static_assert(s2 == "worl", "");
104   constexpr folly::FixedString<5> s3{s, 6u, 5u};
105   static_assert(s3 == "world", "");
106   // Out of bounds count, does not compile:
107   // constexpr folly::FixedString<5> s4{s, 6, 6};
108 }
109
110 TEST(FixedStringCtorTest, FromInitializerList) {
111   constexpr folly::FixedString<11> s{
112       'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'};
113   static_assert(s == "hello world", "");
114   // Out of bounds count, does not compile:
115   // constexpr folly::FixedString<10> s{
116   //     {'h','e','l','l','o',' ','w','o','r','l','d'}};
117 }
118
119 TEST(FixedStringCtorTest, FromUDL) {
120   using namespace folly::Literals;
121 #if defined(__GNUC__)
122   constexpr auto x = "hello"_fs;
123   static_assert(
124       std::is_same<decltype(x), const folly::FixedString<5>>::value, "");
125   static_assert(x[0] == 'h', "");
126   static_assert(x[1] == 'e', "");
127   static_assert(x[2] == 'l', "");
128   static_assert(x[3] == 'l', "");
129   static_assert(x[4] == 'o', "");
130   static_assert(x[5] == '\0', "");
131   static_assert(x.size() == 5u, "");
132 #endif
133
134   constexpr auto y = "goodbye"_fs8;
135   static_assert(
136       std::is_same<decltype(y), const folly::FixedString<8>>::value, "");
137   static_assert(y.size() == 7u, "");
138   static_assert(y == "goodbye", "");
139
140   constexpr auto z = "now is the time for all good llamas"_fs64;
141   static_assert(
142       std::is_same<decltype(z), const folly::FixedString<64>>::value, "");
143   static_assert(z.size() == 35u, "");
144   static_assert(z == "now is the time for all good llamas", "");
145 }
146
147 TEST(FixedStringConcatTest, FromStringAndLiteral) {
148   constexpr folly::FixedString<42> s{"hello world"};
149   constexpr auto res = s + "!!!";
150   static_assert(res.size() == 14u, "");
151   static_assert(res == "hello world!!!", "");
152 }
153
154 TEST(FixedStringConcatTest, FromTwoStrings) {
155   constexpr folly::FixedString<42> s{"hello world"};
156   constexpr auto res = s + "!!!";
157   static_assert(res.size() == 14u, "");
158   static_assert(res == "hello world!!!", "");
159 }
160
161 #if FOLLY_USE_CPP14_CONSTEXPR
162 constexpr folly::FixedString<20> constexpr_swap_test() {
163   folly::FixedString<10> tmp1{"hello"}, tmp2{"world!"};
164   tmp2.swap(tmp1);
165   return tmp1 + tmp2;
166 }
167
168 TEST(FixedStringSwapTest, ConstexprSwap) {
169   static_assert(constexpr_swap_test() == "world!hello", "");
170 }
171 #endif
172
173 TEST(FixedStringSwapTest, RuntimeSwap) {
174   folly::FixedString<10> tmp1{"hello"}, tmp2{"world!"};
175   tmp2.swap(tmp1);
176   EXPECT_STREQ((tmp1 + tmp2).c_str(), "world!hello");
177 }
178
179 #if FOLLY_USE_CPP14_CONSTEXPR
180 constexpr folly::FixedString<10> constexpr_assign_string_test_1() {
181   folly::FixedString<10> tmp1, tmp2{"world!"};
182   tmp1 = tmp2;
183   return tmp1;
184 }
185 constexpr folly::FixedString<10> constexpr_assign_string_test_2() {
186   folly::FixedString<10> tmp{"aaaaaaaaaa"};
187   tmp.assign("hello"_fs8);
188   return tmp;
189 }
190 constexpr folly::FixedString<10> constexpr_assign_string_test_3() {
191   folly::FixedString<10> tmp{"aaaaaaaaaa"};
192   tmp.assign("goodbye"_fs8, 3u, 2u);
193   return tmp;
194 }
195 constexpr folly::FixedString<10> constexpr_assign_string_test_4() {
196   folly::FixedString<10> tmp{"aaaaaaaaaa"};
197   tmp.assign("goodbye"_fs8, 3u, npos);
198   return tmp;
199 }
200
201 TEST(FixedStringAssignTest, ConstexprAssignString) {
202   static_assert(constexpr_assign_string_test_1() == "world!", "");
203   static_assert(constexpr_assign_string_test_2() == "hello", "");
204   static_assert(constexpr_assign_string_test_3() == "db", "");
205   static_assert(constexpr_assign_string_test_4() == "dbye", "");
206 }
207 #endif
208
209 TEST(FixedStringAssignTest, RuntimeAssignString) {
210   folly::FixedString<10> tmp1, tmp2{"world!"};
211   tmp1 = tmp2;
212   EXPECT_STREQ(tmp1.c_str(), "world!");
213   tmp1.assign("goodbye"_fs8);
214   EXPECT_STREQ("goodbye", tmp1.c_str());
215   tmp1.assign("goodbye"_fs8, 3u, npos);
216   EXPECT_STREQ("dbye", tmp1.c_str());
217   tmp1.assign("goodbye"_fs8, 3u, 3u);
218   EXPECT_STREQ("dby", tmp1.c_str());
219 }
220
221 #if FOLLY_USE_CPP14_CONSTEXPR
222 constexpr folly::FixedString<10> constexpr_assign_literal_test_1() {
223   folly::FixedString<10> tmp{"aaaaaaaaaa"};
224   tmp = "hello";
225   // Not null-terminated, does not compile:
226   // using C = const char[1];
227   // tmp = C{'a'};
228   return tmp;
229 }
230 constexpr folly::FixedString<10> constexpr_assign_literal_test_2() {
231   folly::FixedString<10> tmp{"aaaaaaaaaa"};
232   tmp.assign("hello");
233   return tmp;
234 }
235 constexpr folly::FixedString<10> constexpr_assign_literal_test_3() {
236   folly::FixedString<10> tmp{"aaaaaaaaaa"};
237   tmp.assign("goodbye", 4u);
238   return tmp;
239 }
240
241 TEST(FixedStringAssignTest, ConstexprAssignLiteral) {
242   static_assert(constexpr_assign_literal_test_1() == "hello", "");
243   static_assert(constexpr_assign_literal_test_2() == "hello", "");
244   static_assert(constexpr_assign_literal_test_3() == "good", "");
245 }
246 #endif
247
248 TEST(FixedStringAssignTest, RuntimeAssignLiteral) {
249   folly::FixedString<10> tmp{"aaaaaaaaaa"};
250   tmp = "hello";
251   EXPECT_STREQ("hello", tmp.c_str());
252   tmp.assign("goodbye");
253   EXPECT_STREQ("goodbye", tmp.c_str());
254   tmp.assign("goodbye", 4u);
255   EXPECT_STREQ("good", tmp.c_str());
256 }
257
258 TEST(FixedStringIndexTest, Index) {
259   constexpr folly::FixedString<11> digits{"0123456789"};
260   static_assert(digits[0] == '0', "");
261   static_assert(digits[1] == '1', "");
262   static_assert(digits[2] == '2', "");
263   static_assert(digits[9] == '9', "");
264   static_assert(digits[10] == '\0', "");
265   #ifdef NDEBUG
266   // This should be allowed and work in constexpr mode since the internal array
267   // is actually big enough and op[] does no parameter validation:
268   static_assert(digits[11] == '\0', "");
269   #endif
270
271   static_assert(digits.at(0) == '0', "");
272   static_assert(digits.at(1) == '1', "");
273   static_assert(digits.at(2) == '2', "");
274   static_assert(digits.at(9) == '9', "");
275   static_assert(digits.at(10) == '\0', "");
276   EXPECT_THROW(digits.at(11), std::out_of_range);
277 }
278
279 TEST(FixedStringCompareTest, Compare) {
280   constexpr folly::FixedString<10> tmp1{"aaaaaaaaaa"};
281   constexpr folly::FixedString<12> tmp2{"aaaaaaaaaba"};
282   static_assert(-1 == tmp1.compare(tmp2), "");
283   static_assert(1 == tmp2.compare(tmp1), "");
284   static_assert(0 == tmp2.compare(tmp2), "");
285   static_assert(tmp1 < tmp2, "");
286   static_assert(tmp1 <= tmp2, "");
287   static_assert(tmp2 > tmp1, "");
288   static_assert(tmp2 >= tmp1, "");
289   static_assert(tmp2 == tmp2, ""); // @nolint
290   static_assert(tmp2 <= tmp2, ""); // @nolint
291   static_assert(tmp2 >= tmp2, ""); // @nolint
292   static_assert(!(tmp2 < tmp2), "");
293   static_assert(!(tmp2 > tmp2), "");
294
295   constexpr folly::FixedString<10> tmp3{"aaa"};
296   constexpr folly::FixedString<12> tmp4{"aaaa"};
297   static_assert(-1 == tmp3.compare(tmp4), "");
298   static_assert(1 == tmp4.compare(tmp3), "");
299   static_assert(tmp3 < tmp4, "");
300   static_assert(tmp3 <= tmp4, "");
301   static_assert(tmp4 > tmp3, "");
302   static_assert(tmp4 >= tmp3, "");
303   static_assert(tmp3 < "aaaa", "");
304   static_assert(tmp3 <= "aaaa", "");
305   static_assert(!(tmp3 == tmp4), "");
306   static_assert(tmp3 != tmp4, "");
307   static_assert("aaaa" > tmp3, "");
308   static_assert("aaaa" >= tmp3, "");
309   static_assert("aaaa" != tmp3, "");
310   static_assert("aaa" == tmp3, "");
311   static_assert(tmp3 != "aaaa", "");
312   static_assert(tmp3 == "aaa", "");
313 }
314
315 #if FOLLY_USE_CPP14_CONSTEXPR
316 constexpr folly::FixedString<20> constexpr_append_string_test() {
317   folly::FixedString<20> a{"hello"}, b{"X world!"};
318   a.append(1u, ' ');
319   a.append(b, 2u, 5u);
320   a.append(b, 7u, 1u);
321   return a;
322 }
323
324 TEST(FixedStringAssignTest, ConstexprAppendString) {
325   static_assert(constexpr_append_string_test() == "hello world!", "");
326 }
327 #endif
328
329 TEST(FixedStringAssignTest, RuntimeAppendString) {
330   folly::FixedString<20> a{"hello"}, b{"X world!"};
331   a.append(1u, ' ');
332   a.append(b, 2u, 5u);
333   a.append(b, 7u, 1u);
334   EXPECT_STREQ("hello world!", a.c_str());
335 }
336
337 #if FOLLY_USE_CPP14_CONSTEXPR
338 constexpr folly::FixedString<20> constexpr_append_literal_test() {
339   folly::FixedString<20> a{"hello"};
340   a.append(1u, ' ');
341   a.append("X world!" + 2u, 5u);
342   a.append("X world!" + 7u);
343   return a;
344 }
345
346 TEST(FixedStringAssignTest, ConstexprAppendLiteral) {
347   static_assert(constexpr_append_literal_test() == "hello world!", "");
348 }
349 #endif
350
351 TEST(FixedStringAssignTest, RuntimeAppendLiteral) {
352   folly::FixedString<20> a{"hello"};
353   a.append(1u, ' ');
354   a.append("X world!" + 2u, 5u);
355   a.append("X world!" + 7u);
356   EXPECT_STREQ("hello world!", a.c_str());
357 }
358
359 TEST(FixedStringCAppendTest, CAppendString) {
360   constexpr folly::FixedString<10> a{"hello"}, b{"X world!"};
361   constexpr auto tmp1 = a.cappend(' ');
362   constexpr auto tmp2 = tmp1.cappend(b, 2u, 5u);
363   constexpr auto tmp3 = tmp2.cappend(b, 7u, 1u);
364   static_assert(tmp3 == "hello world!", "");
365 }
366
367 TEST(FixedStringCAppendTest, CAppendLiteral) {
368   constexpr folly::FixedString<10> a{"hello"};
369   constexpr auto tmp1 = a.cappend(' ');
370   constexpr auto tmp2 = tmp1.cappend("X world!", 2u, 5u);
371   constexpr auto tmp3 = tmp2.cappend("X world!", 7u, 1u);
372   static_assert(tmp3 == "hello world!", "");
373 }
374
375 #if FOLLY_USE_CPP14_CONSTEXPR
376 constexpr folly::FixedString<10> constexpr_replace_string_test() {
377   folly::FixedString<10> tmp{"abcdefghij"};
378   tmp.replace(1, 5, FS("XX"));
379   return tmp;
380 }
381
382 TEST(FixedStringReplaceTest, ConstexprReplaceString) {
383   static_assert(constexpr_replace_string_test().size() == 7u, "");
384   static_assert(constexpr_replace_string_test() == "aXXghij", "");
385 }
386 #endif
387
388 TEST(FixedStringReplaceTest, RuntimeReplaceString) {
389   folly::FixedString<10> tmp{"abcdefghij"};
390   tmp.replace(1, 5, FS("XX"));
391   EXPECT_EQ(7u, tmp.size());
392   EXPECT_STREQ("aXXghij", tmp.c_str());
393 }
394
395 TEST(FixedStringEraseTest, RuntimeEraseTest) {
396   auto x = FS("abcdefghijklmnopqrstuvwxyz"), y = x;
397   x.erase(x.size());
398   EXPECT_EQ(26u, x.size());
399   EXPECT_STREQ(y.c_str(), x.c_str());
400   x.erase(25u).erase(24u);
401   EXPECT_EQ(24u, x.size());
402   EXPECT_STREQ("abcdefghijklmnopqrstuvwx", x.c_str());
403   x.erase(1u, x.size() - 2u);
404   EXPECT_EQ(2u, x.size());
405   EXPECT_STREQ("ax", x.c_str());
406 }
407
408 TEST(FixedStringEraseTest, CEraseTest) {
409   constexpr auto x = FS("abcdefghijklmnopqrstuvwxyz"), y = x;
410   constexpr auto tmp0 = x.cerase(x.size());
411   static_assert(26u == tmp0.size(), "");
412   static_assert(y == tmp0, "");
413   constexpr auto tmp1 = tmp0.cerase(25u).cerase(24u);
414   static_assert(24u == tmp1.size(), "");
415   static_assert("abcdefghijklmnopqrstuvwx" == tmp1, "");
416   constexpr auto tmp2 = tmp1.cerase(1u, tmp1.size() - 2u);
417   static_assert(2u == tmp2.size(), "");
418   static_assert("ax" == tmp2, "");
419   constexpr auto tmp3 = tmp2.cerase();
420   static_assert("" == tmp3, "");
421 }
422
423 TEST(FixedStringFindTest, FindString) {
424   constexpr folly::FixedString<10> tmp{"hijdefghij"};
425   static_assert(tmp.find(FS("hij")) == 0u, "");
426   static_assert(tmp.find(FS("hij"), 1u) == 7u, "");
427   static_assert(tmp.find(FS("hijdefghij")) == 0u, "");
428   static_assert(tmp.find(FS("")) == 0u, "");
429 }
430
431 TEST(FixedStringFindTest, FindLiteral) {
432   constexpr folly::FixedString<10> tmp{"hijdefghij"};
433   static_assert(tmp.find("hij") == 0u, "");
434   static_assert(tmp.find("hij", 1u) == 7u, "");
435   static_assert(tmp.find("hijdefghij") == 0u, "");
436 }
437
438 TEST(FixedStringReverseFindTest, FindChar) {
439   constexpr folly::FixedString<16> tmp{"This is a string"};
440   static_assert(tmp.find('s') == 3u, "");
441   static_assert(tmp.find('s', 9u) == 10u, "");
442   static_assert(tmp.find('s', 10u) == 10u, "");
443   static_assert(tmp.find('s', 11u) == tmp.npos, "");
444 }
445
446 TEST(FixedStringReverseFindTest, ReverseFindString) {
447   constexpr folly::FixedString<16> tmp{"This is a string"};
448   static_assert(tmp.rfind(FS("is")) == 5u, "");
449   static_assert(tmp.rfind(FS("is"), 4u) == 2u, "");
450   static_assert(tmp.rfind(FS("This is a string")) == 0u, "");
451   static_assert(tmp.rfind(FS("This is a string!")) == tmp.npos, "");
452   static_assert(tmp.rfind(FS("")) == 16u, "");
453 }
454
455 TEST(FixedStringReverseFindTest, ReverseFindLiteral) {
456   constexpr folly::FixedString<16> tmp{"This is a string"};
457   static_assert(tmp.rfind("is") == 5u, "");
458   static_assert(tmp.rfind("is", 4u) == 2u, "");
459   static_assert(tmp.rfind("This is a string") == 0u, "");
460   static_assert(tmp.rfind("This is a string!") == tmp.npos, "");
461   static_assert(tmp.rfind("") == 16u, "");
462 }
463
464 TEST(FixedStringReverseFindTest, ReverseFindChar) {
465   constexpr folly::FixedString<16> tmp{"This is a string"};
466   static_assert(tmp.rfind('s') == 10u, "");
467   static_assert(tmp.rfind('s', 5u) == 3u, "");
468   static_assert(tmp.rfind('s', 3u) == 3u, "");
469   static_assert(tmp.rfind('s', 2u) == tmp.npos, "");
470 }
471
472 TEST(FixedStringFindFirstOfTest, FindFirstOfString) {
473   constexpr folly::FixedString<16> tmp{"This is a string"};
474   static_assert(tmp.find_first_of(FS("hi")) == 1u, "");
475   static_assert(tmp.find_first_of(FS("xi")) == 2u, "");
476   static_assert(tmp.find_first_of(FS("xi"), 6u) == 13u, "");
477   static_assert(tmp.find_first_of(FS("xz")) == tmp.npos, "");
478   static_assert(FS("a").find_first_of(FS("cba")) == 0u, "");
479   static_assert(FS("").find_first_of(FS("cba")) == tmp.npos, "");
480   static_assert(FS("a").find_first_of(FS("")) == tmp.npos, "");
481   static_assert(FS("").find_first_of(FS("")) == tmp.npos, "");
482 }
483
484 TEST(FixedStringFindFirstOfTest, FindFirstOfLiteral) {
485   constexpr folly::FixedString<16> tmp{"This is a string"};
486   static_assert(tmp.find_first_of("hi") == 1u, "");
487   static_assert(tmp.find_first_of("xi") == 2u, "");
488   static_assert(tmp.find_first_of("xi", 6u) == 13u, "");
489   static_assert(tmp.find_first_of("xis", 6u, 2u) == 13u, "");
490   static_assert(tmp.find_first_of("xz") == tmp.npos, "");
491   static_assert(FS("a").find_first_of("cba") == 0u, "");
492   static_assert(FS("").find_first_of("cba") == tmp.npos, "");
493   static_assert(FS("a").find_first_of("") == tmp.npos, "");
494   static_assert(FS("").find_first_of("") == tmp.npos, "");
495 }
496
497 TEST(FixedStringFindFirstOfTest, FindFirstOfChar) {
498   constexpr folly::FixedString<16> tmp{"This is a string"};
499   static_assert(tmp.find_first_of('h') == 1u, "");
500   static_assert(tmp.find_first_of('i') == 2u, "");
501   static_assert(tmp.find_first_of('i', 6u) == 13u, "");
502   static_assert(tmp.find_first_of('x') == tmp.npos, "");
503   static_assert(FS("a").find_first_of('a') == 0u, "");
504   static_assert(FS("").find_first_of('a') == tmp.npos, "");
505 }
506
507 TEST(FixedStringFindFirstNotOfTest, FindFirstNotOfString) {
508   constexpr folly::FixedString<16> tmp{"This is a string"};
509   static_assert(tmp.find_first_not_of(FS("Ti")) == 1u, "");
510   static_assert(tmp.find_first_not_of(FS("hT")) == 2u, "");
511   static_assert(tmp.find_first_not_of(FS("s atr"), 6u) == 13u, "");
512   static_assert(tmp.find_first_not_of(FS("This atrng")) == tmp.npos, "");
513   static_assert(FS("a").find_first_not_of(FS("X")) == 0u, "");
514   static_assert(FS("").find_first_not_of(FS("cba")) == tmp.npos, "");
515   static_assert(FS("a").find_first_not_of(FS("")) == 0u, "");
516   static_assert(FS("").find_first_not_of(FS("")) == tmp.npos, "");
517 }
518
519 TEST(FixedStringFindFirstNotOfTest, FindFirstNotOfLiteral) {
520   constexpr folly::FixedString<16> tmp{"This is a string"};
521   static_assert(tmp.find_first_not_of("Ti") == 1u, "");
522   static_assert(tmp.find_first_not_of("hT") == 2u, "");
523   static_assert(tmp.find_first_not_of("s atr", 6u) == 13u, "");
524   static_assert(tmp.find_first_not_of("This atrng") == tmp.npos, "");
525   static_assert(FS("a").find_first_not_of("X") == 0u, "");
526   static_assert(FS("").find_first_not_of("cba") == tmp.npos, "");
527   static_assert(FS("a").find_first_not_of("") == 0u, "");
528   static_assert(FS("").find_first_not_of("") == tmp.npos, "");
529 }
530
531 TEST(FixedStringFindFirstNotOfTest, FindFirstNotOfChar) {
532   constexpr folly::FixedString<16> tmp{"This is a string"};
533   static_assert(tmp.find_first_not_of('T') == 1u, "");
534   static_assert(tmp.find_first_not_of('i') == 0u, "");
535   static_assert(tmp.find_first_not_of('x', 6u) == 6u, "");
536   static_assert(tmp.find_first_not_of('s', 6u) == 7u, "");
537   static_assert(FS("a").find_first_not_of('a') == tmp.npos, "");
538   static_assert(FS("").find_first_not_of('a') == tmp.npos, "");
539 }
540
541 TEST(FixedStringFindLastOfTest, FindLastOfString) {
542   constexpr folly::FixedString<16> tmp{"This is a string"};
543   static_assert(tmp.find_last_of(FS("hi")) == 13u, "");
544   static_assert(tmp.find_last_of(FS("xh")) == 1u, "");
545   static_assert(tmp.find_last_of(FS("xi"), 6u) == 5u, "");
546   static_assert(tmp.find_last_of(FS("xz")) == tmp.npos, "");
547   static_assert(FS("a").find_last_of(FS("cba")) == 0u, "");
548   static_assert(FS("").find_last_of(FS("cba")) == tmp.npos, "");
549   static_assert(FS("a").find_last_of(FS("")) == tmp.npos, "");
550   static_assert(FS("").find_last_of(FS("")) == tmp.npos, "");
551 }
552
553 TEST(FixedStringFindLastOfTest, FindLastOfLiteral) {
554   constexpr folly::FixedString<16> tmp{"This is a string"};
555   static_assert(tmp.find_last_of("hi") == 13u, "");
556   static_assert(tmp.find_last_of("xh") == 1u, "");
557   static_assert(tmp.find_last_of("xi", 6u) == 5u, "");
558   static_assert(tmp.find_last_of("xis", 6u, 2u) == 5u, "");
559   static_assert(tmp.find_last_of("xz") == tmp.npos, "");
560   static_assert(FS("a").find_last_of("cba") == 0u, "");
561   static_assert(FS("").find_last_of("cba") == tmp.npos, "");
562   static_assert(FS("a").find_last_of("") == tmp.npos, "");
563   static_assert(FS("").find_last_of("") == tmp.npos, "");
564 }
565
566 TEST(FixedStringFindLastOfTest, FindLastOfChar) {
567   constexpr folly::FixedString<16> tmp{"This is a string"};
568   static_assert(tmp.find_last_of('h') == 1u, "");
569   static_assert(tmp.find_last_of('i') == 13u, "");
570   static_assert(tmp.find_last_of('i', 6u) == 5u, "");
571   static_assert(tmp.find_last_of('x') == tmp.npos, "");
572   static_assert(FS("a").find_last_of('a') == 0u, "");
573   static_assert(FS("").find_last_of('a') == tmp.npos, "");
574 }
575
576 TEST(FixedStringFindLastNotOfTest, FindLastNotOfString) {
577   constexpr folly::FixedString<16> tmp{"This is a string"};
578   static_assert(tmp.find_last_not_of(FS("gstrin")) == 9u, "");
579   static_assert(tmp.find_last_not_of(FS("hT")) == 15u, "");
580   static_assert(tmp.find_last_not_of(FS("s atr"), 6u) == 5u, "");
581   static_assert(tmp.find_last_not_of(FS("This atrng")) == tmp.npos, "");
582   static_assert(FS("a").find_last_not_of(FS("X")) == 0u, "");
583   static_assert(FS("").find_last_not_of(FS("cba")) == tmp.npos, "");
584   static_assert(FS("a").find_last_not_of(FS("")) == 0u, "");
585   static_assert(FS("").find_last_not_of(FS("")) == tmp.npos, "");
586 }
587
588 TEST(FixedStringFindLastNotOfTest, FindLastNotOfLiteral) {
589   constexpr folly::FixedString<16> tmp{"This is a string"};
590   static_assert(tmp.find_last_not_of("gstrin") == 9u, "");
591   static_assert(tmp.find_last_not_of("hT") == 15u, "");
592   static_assert(tmp.find_last_not_of("s atr", 6u) == 5u, "");
593   static_assert(tmp.find_last_not_of(" atrs", 6u, 4u) == 6u, "");
594   static_assert(tmp.find_last_not_of("This atrng") == tmp.npos, "");
595   static_assert(FS("a").find_last_not_of("X") == 0u, "");
596   static_assert(FS("").find_last_not_of("cba") == tmp.npos, "");
597   static_assert(FS("a").find_last_not_of("") == 0u, "");
598   static_assert(FS("").find_last_not_of("") == tmp.npos, "");
599 }
600
601 TEST(FixedStringFindLastNotOfTest, FindLastNotOfChar) {
602   constexpr folly::FixedString<16> tmp{"This is a string"};
603   static_assert(tmp.find_last_not_of('g') == 14u, "");
604   static_assert(tmp.find_last_not_of('i') == 15u, "");
605   static_assert(tmp.find_last_not_of('x', 6u) == 6u, "");
606   static_assert(tmp.find_last_not_of('s', 6u) == 5u, "");
607   static_assert(FS("a").find_last_not_of('a') == tmp.npos, "");
608   static_assert(FS("").find_last_not_of('a') == tmp.npos, "");
609 }
610
611 TEST(FixedStringConversionTest, ConversionToStdString) {
612   constexpr folly::FixedString<16> tmp{"This is a string"};
613   std::string str = tmp;
614   EXPECT_STREQ("This is a string", str.c_str());
615   str = "another string"_fs16;
616   EXPECT_STREQ("another string", str.c_str());
617 }
618
619 #if FOLLY_USE_CPP14_CONSTEXPR
620 constexpr std::size_t countSpacesReverse(folly::FixedString<50> s) {
621   std::size_t count = 0u;
622   auto i = s.rbegin();
623   for( ; i != s.rend(); ++i, --i, i++, i--, i+=1, i-=1, i+=1 ) {
624     if (' ' == *i)
625       ++count;
626   }
627   return count;
628 }
629
630 TEST(FixedStringReverseIteratorTest, Cpp14ConstexprReverseIteration) {
631   static_assert(3 == countSpacesReverse("This is a string"), "");
632 }
633 #endif
634
635 TEST(FixedStringReverseIteratorTest, ConstexprReverseIteration) {
636   static constexpr auto alpha = FS("abcdefghijklmnopqrstuvwxyz");
637   static_assert('a' == alpha.rbegin()[25], "");
638   static_assert('a' == *(alpha.rbegin() + 25), "");
639   static_assert('c' == *(alpha.rbegin() + 25 - 2), "");
640   static_assert((alpha.rend() - 2) == (alpha.rbegin() + 24), "");
641 }
642
643 #include <folly/Range.h>
644
645 TEST(FixedStringConversionTest, ConversionToFollyRange) {
646   // The following declaraction is static for compilers that haven't implemented
647   // the resolution of:
648   // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1454
649   static constexpr folly::FixedString<16> tmp{"This is a string"};
650   constexpr folly::StringPiece piece = tmp;
651   static_assert(tmp.begin() == piece.begin(), "");
652   static_assert(tmp.end() == piece.end(), "");
653 }