1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "absl/strings/internal/char_map.h"
16 
17 #include <cctype>
18 #include <string>
19 #include <vector>
20 
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 
24 namespace {
25 
26 constexpr absl::strings_internal::Charmap everything_map =
27     ~absl::strings_internal::Charmap();
28 constexpr absl::strings_internal::Charmap nothing_map{};
29 
TEST(Charmap,AllTests)30 TEST(Charmap, AllTests) {
31   const absl::strings_internal::Charmap also_nothing_map("", 0);
32   ASSERT_TRUE(everything_map.contains('\0'));
33   ASSERT_TRUE(!nothing_map.contains('\0'));
34   ASSERT_TRUE(!also_nothing_map.contains('\0'));
35   for (unsigned char ch = 1; ch != 0; ++ch) {
36     ASSERT_TRUE(everything_map.contains(ch));
37     ASSERT_TRUE(!nothing_map.contains(ch));
38     ASSERT_TRUE(!also_nothing_map.contains(ch));
39   }
40 
41   const absl::strings_internal::Charmap symbols("&@#@^!@?", 5);
42   ASSERT_TRUE(symbols.contains('&'));
43   ASSERT_TRUE(symbols.contains('@'));
44   ASSERT_TRUE(symbols.contains('#'));
45   ASSERT_TRUE(symbols.contains('^'));
46   ASSERT_TRUE(!symbols.contains('!'));
47   ASSERT_TRUE(!symbols.contains('?'));
48   int cnt = 0;
49   for (unsigned char ch = 1; ch != 0; ++ch)
50     cnt += symbols.contains(ch);
51   ASSERT_EQ(cnt, 4);
52 
53   const absl::strings_internal::Charmap lets("^abcde", 3);
54   const absl::strings_internal::Charmap lets2("fghij\0klmnop", 10);
55   const absl::strings_internal::Charmap lets3("fghij\0klmnop");
56   ASSERT_TRUE(lets2.contains('k'));
57   ASSERT_TRUE(!lets3.contains('k'));
58 
59   ASSERT_TRUE(symbols.IntersectsWith(lets));
60   ASSERT_TRUE(!lets2.IntersectsWith(lets));
61   ASSERT_TRUE(lets.IntersectsWith(symbols));
62   ASSERT_TRUE(!lets.IntersectsWith(lets2));
63 
64   ASSERT_TRUE(nothing_map.IsZero());
65   ASSERT_TRUE(!lets.IsZero());
66 }
67 
68 namespace {
Members(const absl::strings_internal::Charmap & m)69 std::string Members(const absl::strings_internal::Charmap& m) {
70   std::string r;
71   for (size_t i = 0; i < 256; ++i)
72     if (m.contains(i)) r.push_back(i);
73   return r;
74 }
75 
ClosedRangeString(unsigned char lo,unsigned char hi)76 std::string ClosedRangeString(unsigned char lo, unsigned char hi) {
77   // Don't depend on lo<hi. Just increment until lo==hi.
78   std::string s;
79   while (true) {
80     s.push_back(lo);
81     if (lo == hi) break;
82     ++lo;
83   }
84   return s;
85 }
86 
87 }  // namespace
88 
TEST(Charmap,Constexpr)89 TEST(Charmap, Constexpr) {
90   constexpr absl::strings_internal::Charmap kEmpty = nothing_map;
91   EXPECT_THAT(Members(kEmpty), "");
92   constexpr absl::strings_internal::Charmap kA =
93       absl::strings_internal::Charmap::Char('A');
94   EXPECT_THAT(Members(kA), "A");
95   constexpr absl::strings_internal::Charmap kAZ =
96       absl::strings_internal::Charmap::Range('A', 'Z');
97   EXPECT_THAT(Members(kAZ), "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
98   constexpr absl::strings_internal::Charmap kIdentifier =
99       absl::strings_internal::Charmap::Range('0', '9') |
100       absl::strings_internal::Charmap::Range('A', 'Z') |
101       absl::strings_internal::Charmap::Range('a', 'z') |
102       absl::strings_internal::Charmap::Char('_');
103   EXPECT_THAT(Members(kIdentifier),
104               "0123456789"
105               "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
106               "_"
107               "abcdefghijklmnopqrstuvwxyz");
108   constexpr absl::strings_internal::Charmap kAll = everything_map;
109   for (size_t i = 0; i < 256; ++i) {
110     EXPECT_TRUE(kAll.contains(i)) << i;
111   }
112   constexpr absl::strings_internal::Charmap kHello =
113       absl::strings_internal::Charmap::FromString("Hello, world!");
114   EXPECT_THAT(Members(kHello), " !,Hdelorw");
115 
116   // test negation and intersection
117   constexpr absl::strings_internal::Charmap kABC =
118       absl::strings_internal::Charmap::Range('A', 'Z') &
119       ~absl::strings_internal::Charmap::Range('D', 'Z');
120   EXPECT_THAT(Members(kABC), "ABC");
121 }
122 
TEST(Charmap,Range)123 TEST(Charmap, Range) {
124   // Exhaustive testing takes too long, so test some of the boundaries that
125   // are perhaps going to cause trouble.
126   std::vector<size_t> poi = {0,   1,   2,   3,   4,   7,   8,   9,  15,
127                              16,  17,  30,  31,  32,  33,  63,  64, 65,
128                              127, 128, 129, 223, 224, 225, 254, 255};
129   for (auto lo = poi.begin(); lo != poi.end(); ++lo) {
130     SCOPED_TRACE(*lo);
131     for (auto hi = lo; hi != poi.end(); ++hi) {
132       SCOPED_TRACE(*hi);
133       EXPECT_THAT(Members(absl::strings_internal::Charmap::Range(*lo, *hi)),
134                   ClosedRangeString(*lo, *hi));
135     }
136   }
137 }
138 
AsBool(int x)139 bool AsBool(int x) { return static_cast<bool>(x); }
140 
TEST(CharmapCtype,Match)141 TEST(CharmapCtype, Match) {
142   for (int c = 0; c < 256; ++c) {
143     SCOPED_TRACE(c);
144     SCOPED_TRACE(static_cast<char>(c));
145     EXPECT_EQ(AsBool(std::isupper(c)),
146               absl::strings_internal::UpperCharmap().contains(c));
147     EXPECT_EQ(AsBool(std::islower(c)),
148               absl::strings_internal::LowerCharmap().contains(c));
149     EXPECT_EQ(AsBool(std::isdigit(c)),
150               absl::strings_internal::DigitCharmap().contains(c));
151     EXPECT_EQ(AsBool(std::isalpha(c)),
152               absl::strings_internal::AlphaCharmap().contains(c));
153     EXPECT_EQ(AsBool(std::isalnum(c)),
154               absl::strings_internal::AlnumCharmap().contains(c));
155     EXPECT_EQ(AsBool(std::isxdigit(c)),
156               absl::strings_internal::XDigitCharmap().contains(c));
157     EXPECT_EQ(AsBool(std::isprint(c)),
158               absl::strings_internal::PrintCharmap().contains(c));
159     EXPECT_EQ(AsBool(std::isspace(c)),
160               absl::strings_internal::SpaceCharmap().contains(c));
161     EXPECT_EQ(AsBool(std::iscntrl(c)),
162               absl::strings_internal::CntrlCharmap().contains(c));
163     EXPECT_EQ(AsBool(std::isblank(c)),
164               absl::strings_internal::BlankCharmap().contains(c));
165     EXPECT_EQ(AsBool(std::isgraph(c)),
166               absl::strings_internal::GraphCharmap().contains(c));
167     EXPECT_EQ(AsBool(std::ispunct(c)),
168               absl::strings_internal::PunctCharmap().contains(c));
169   }
170 }
171 
172 }  // namespace
173