| // Copyright 2020 The Abseil Authors. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "absl/strings/charset.h" | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string> | |
| #include <vector> | |
| #include "gtest/gtest.h" | |
| #include "absl/strings/ascii.h" | |
| #include "absl/strings/string_view.h" | |
| namespace { | |
| constexpr absl::CharSet everything_map = ~absl::CharSet(); | |
| constexpr absl::CharSet nothing_map = absl::CharSet(); | |
| TEST(Charmap, AllTests) { | |
| const absl::CharSet also_nothing_map(""); | |
| EXPECT_TRUE(everything_map.contains('\0')); | |
| EXPECT_FALSE(nothing_map.contains('\0')); | |
| EXPECT_FALSE(also_nothing_map.contains('\0')); | |
| for (unsigned char ch = 1; ch != 0; ++ch) { | |
| SCOPED_TRACE(ch); | |
| EXPECT_TRUE(everything_map.contains(ch)); | |
| EXPECT_FALSE(nothing_map.contains(ch)); | |
| EXPECT_FALSE(also_nothing_map.contains(ch)); | |
| } | |
| const absl::CharSet symbols(absl::string_view("&@#@^!@?", 5)); | |
| EXPECT_TRUE(symbols.contains('&')); | |
| EXPECT_TRUE(symbols.contains('@')); | |
| EXPECT_TRUE(symbols.contains('#')); | |
| EXPECT_TRUE(symbols.contains('^')); | |
| EXPECT_FALSE(symbols.contains('!')); | |
| EXPECT_FALSE(symbols.contains('?')); | |
| int cnt = 0; | |
| for (unsigned char ch = 1; ch != 0; ++ch) cnt += symbols.contains(ch); | |
| EXPECT_EQ(cnt, 4); | |
| const absl::CharSet lets(absl::string_view("^abcde", 3)); | |
| const absl::CharSet lets2(absl::string_view("fghij\0klmnop", 10)); | |
| const absl::CharSet lets3("fghij\0klmnop"); | |
| EXPECT_TRUE(lets2.contains('k')); | |
| EXPECT_FALSE(lets3.contains('k')); | |
| EXPECT_FALSE((symbols & lets).empty()); | |
| EXPECT_TRUE((lets2 & lets).empty()); | |
| EXPECT_FALSE((lets & symbols).empty()); | |
| EXPECT_TRUE((lets & lets2).empty()); | |
| EXPECT_TRUE(nothing_map.empty()); | |
| EXPECT_FALSE(lets.empty()); | |
| } | |
| std::string Members(const absl::CharSet& m) { | |
| std::string r; | |
| for (size_t i = 0; i < 256; ++i) | |
| if (m.contains(i)) r.push_back(i); | |
| return r; | |
| } | |
| std::string ClosedRangeString(unsigned char lo, unsigned char hi) { | |
| // Don't depend on lo<hi. Just increment until lo==hi. | |
| std::string s; | |
| while (true) { | |
| s.push_back(lo); | |
| if (lo == hi) break; | |
| ++lo; | |
| } | |
| return s; | |
| } | |
| TEST(Charmap, Constexpr) { | |
| constexpr absl::CharSet kEmpty = absl::CharSet(); | |
| EXPECT_EQ(Members(kEmpty), ""); | |
| constexpr absl::CharSet kA = absl::CharSet::Char('A'); | |
| EXPECT_EQ(Members(kA), "A"); | |
| constexpr absl::CharSet kAZ = absl::CharSet::Range('A', 'Z'); | |
| EXPECT_EQ(Members(kAZ), "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); | |
| constexpr absl::CharSet kIdentifier = | |
| absl::CharSet::Range('0', '9') | absl::CharSet::Range('A', 'Z') | | |
| absl::CharSet::Range('a', 'z') | absl::CharSet::Char('_'); | |
| EXPECT_EQ(Members(kIdentifier), | |
| "0123456789" | |
| "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
| "_" | |
| "abcdefghijklmnopqrstuvwxyz"); | |
| constexpr absl::CharSet kAll = ~absl::CharSet(); | |
| for (size_t i = 0; i < 256; ++i) { | |
| SCOPED_TRACE(i); | |
| EXPECT_TRUE(kAll.contains(i)); | |
| } | |
| constexpr absl::CharSet kHello = absl::CharSet("Hello, world!"); | |
| EXPECT_EQ(Members(kHello), " !,Hdelorw"); | |
| // test negation and intersection | |
| constexpr absl::CharSet kABC = | |
| absl::CharSet::Range('A', 'Z') & ~absl::CharSet::Range('D', 'Z'); | |
| EXPECT_EQ(Members(kABC), "ABC"); | |
| // contains | |
| constexpr bool kContainsA = absl::CharSet("abc").contains('a'); | |
| EXPECT_TRUE(kContainsA); | |
| constexpr bool kContainsD = absl::CharSet("abc").contains('d'); | |
| EXPECT_FALSE(kContainsD); | |
| // empty | |
| constexpr bool kEmptyIsEmpty = absl::CharSet().empty(); | |
| EXPECT_TRUE(kEmptyIsEmpty); | |
| constexpr bool kNotEmptyIsEmpty = absl::CharSet("abc").empty(); | |
| EXPECT_FALSE(kNotEmptyIsEmpty); | |
| } | |
| TEST(Charmap, Range) { | |
| // Exhaustive testing takes too long, so test some of the boundaries that | |
| // are perhaps going to cause trouble. | |
| std::vector<size_t> poi = {0, 1, 2, 3, 4, 7, 8, 9, 15, | |
| 16, 17, 30, 31, 32, 33, 63, 64, 65, | |
| 127, 128, 129, 223, 224, 225, 254, 255}; | |
| for (auto lo = poi.begin(); lo != poi.end(); ++lo) { | |
| SCOPED_TRACE(*lo); | |
| for (auto hi = lo; hi != poi.end(); ++hi) { | |
| SCOPED_TRACE(*hi); | |
| EXPECT_EQ(Members(absl::CharSet::Range(*lo, *hi)), | |
| ClosedRangeString(*lo, *hi)); | |
| } | |
| } | |
| } | |
| TEST(Charmap, NullByteWithStringView) { | |
| char characters[5] = {'a', 'b', '\0', 'd', 'x'}; | |
| absl::string_view view(characters, 5); | |
| absl::CharSet tester(view); | |
| EXPECT_TRUE(tester.contains('a')); | |
| EXPECT_TRUE(tester.contains('b')); | |
| EXPECT_TRUE(tester.contains('\0')); | |
| EXPECT_TRUE(tester.contains('d')); | |
| EXPECT_TRUE(tester.contains('x')); | |
| EXPECT_FALSE(tester.contains('c')); | |
| } | |
| TEST(CharmapCtype, Match) { | |
| for (int c = 0; c < 256; ++c) { | |
| SCOPED_TRACE(c); | |
| SCOPED_TRACE(static_cast<char>(c)); | |
| EXPECT_EQ(absl::ascii_isupper(c), | |
| absl::CharSet::AsciiUppercase().contains(c)); | |
| EXPECT_EQ(absl::ascii_islower(c), | |
| absl::CharSet::AsciiLowercase().contains(c)); | |
| EXPECT_EQ(absl::ascii_isdigit(c), absl::CharSet::AsciiDigits().contains(c)); | |
| EXPECT_EQ(absl::ascii_isalpha(c), | |
| absl::CharSet::AsciiAlphabet().contains(c)); | |
| EXPECT_EQ(absl::ascii_isalnum(c), | |
| absl::CharSet::AsciiAlphanumerics().contains(c)); | |
| EXPECT_EQ(absl::ascii_isxdigit(c), | |
| absl::CharSet::AsciiHexDigits().contains(c)); | |
| EXPECT_EQ(absl::ascii_isprint(c), | |
| absl::CharSet::AsciiPrintable().contains(c)); | |
| EXPECT_EQ(absl::ascii_isspace(c), | |
| absl::CharSet::AsciiWhitespace().contains(c)); | |
| EXPECT_EQ(absl::ascii_ispunct(c), | |
| absl::CharSet::AsciiPunctuation().contains(c)); | |
| } | |
| } | |
| } // namespace |