1 | //===-- Tests for str{,r}chr and {,r}index functions ------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "test/UnitTest/Test.h" |
10 | |
11 | template <auto Func> struct StrchrTest : public LIBC_NAMESPACE::testing::Test { |
12 | void findsFirstCharacter() { |
13 | const char *src = "abcde" ; |
14 | |
15 | // Should return original string since 'a' is the first character. |
16 | ASSERT_STREQ(Func(src, 'a'), "abcde" ); |
17 | // Source string should not change. |
18 | ASSERT_STREQ(src, "abcde" ); |
19 | } |
20 | |
21 | void findsMiddleCharacter() { |
22 | const char *src = "abcde" ; |
23 | |
24 | // Should return characters after (and including) 'c'. |
25 | ASSERT_STREQ(Func(src, 'c'), "cde" ); |
26 | // Source string should not change. |
27 | ASSERT_STREQ(src, "abcde" ); |
28 | } |
29 | |
30 | void findsLastCharacterThatIsNotNullTerminator() { |
31 | const char *src = "abcde" ; |
32 | |
33 | // Should return 'e' and null-terminator. |
34 | ASSERT_STREQ(Func(src, 'e'), "e" ); |
35 | // Source string should not change. |
36 | ASSERT_STREQ(src, "abcde" ); |
37 | } |
38 | |
39 | void findsNullTerminator() { |
40 | const char *src = "abcde" ; |
41 | |
42 | // Should return null terminator. |
43 | ASSERT_STREQ(Func(src, '\0'), "" ); |
44 | // Source string should not change. |
45 | ASSERT_STREQ(src, "abcde" ); |
46 | } |
47 | |
48 | void characterNotWithinStringShouldReturnNullptr() { |
49 | // Since 'z' is not within the string, should return nullptr. |
50 | ASSERT_STREQ(Func("123?" , 'z'), nullptr); |
51 | } |
52 | |
53 | void theSourceShouldNotChange() { |
54 | const char *src = "abcde" ; |
55 | // When the character is found, the source string should not change. |
56 | Func(src, 'd'); |
57 | ASSERT_STREQ(src, "abcde" ); |
58 | // Same case for when the character is not found. |
59 | Func(src, 'z'); |
60 | ASSERT_STREQ(src, "abcde" ); |
61 | // Same case for when looking for nullptr. |
62 | Func(src, '\0'); |
63 | ASSERT_STREQ(src, "abcde" ); |
64 | } |
65 | |
66 | void shouldFindFirstOfDuplicates() { |
67 | // '1' is duplicated in the string, but it should find the first copy. |
68 | ASSERT_STREQ(Func("abc1def1ghi" , '1'), "1def1ghi" ); |
69 | |
70 | const char *dups = "XXXXX" ; |
71 | // Should return original string since 'X' is the first character. |
72 | ASSERT_STREQ(Func(dups, 'X'), dups); |
73 | } |
74 | |
75 | void emptyStringShouldOnlyMatchNullTerminator() { |
76 | // Null terminator should match. |
77 | ASSERT_STREQ(Func("" , '\0'), "" ); |
78 | // All other characters should not match. |
79 | ASSERT_STREQ(Func("" , 'Z'), nullptr); |
80 | ASSERT_STREQ(Func("" , '3'), nullptr); |
81 | ASSERT_STREQ(Func("" , '*'), nullptr); |
82 | } |
83 | }; |
84 | |
85 | template <auto Func> struct StrrchrTest : public LIBC_NAMESPACE::testing::Test { |
86 | void findsFirstCharacter() { |
87 | const char *src = "abcde" ; |
88 | |
89 | // Should return original string since 'a' is the first character. |
90 | ASSERT_STREQ(Func(src, 'a'), "abcde" ); |
91 | // Source string should not change. |
92 | ASSERT_STREQ(src, "abcde" ); |
93 | } |
94 | |
95 | void findsMiddleCharacter() { |
96 | const char *src = "abcde" ; |
97 | |
98 | // Should return characters after (and including) 'c'. |
99 | ASSERT_STREQ(Func(src, 'c'), "cde" ); |
100 | // Source string should not change. |
101 | ASSERT_STREQ(src, "abcde" ); |
102 | } |
103 | |
104 | void findsLastCharacterThatIsNotNullTerminator() { |
105 | const char *src = "abcde" ; |
106 | |
107 | // Should return 'e' and null-terminator. |
108 | ASSERT_STREQ(Func(src, 'e'), "e" ); |
109 | // Source string should not change. |
110 | ASSERT_STREQ(src, "abcde" ); |
111 | } |
112 | |
113 | void findsNullTerminator() { |
114 | const char *src = "abcde" ; |
115 | |
116 | // Should return null terminator. |
117 | ASSERT_STREQ(Func(src, '\0'), "" ); |
118 | // Source string should not change. |
119 | ASSERT_STREQ(src, "abcde" ); |
120 | } |
121 | |
122 | void findsLastBehindFirstNullTerminator() { |
123 | static const char src[6] = {'a', 'a', '\0', 'b', '\0', 'c'}; |
124 | // 'b' is behind a null terminator, so should not be found. |
125 | ASSERT_STREQ(Func(src, 'b'), nullptr); |
126 | // Same goes for 'c'. |
127 | ASSERT_STREQ(Func(src, 'c'), nullptr); |
128 | |
129 | // Should find the second of the two a's. |
130 | ASSERT_STREQ(Func(src, 'a'), "a" ); |
131 | } |
132 | |
133 | void characterNotWithinStringShouldReturnNullptr() { |
134 | // Since 'z' is not within the string, should return nullptr. |
135 | ASSERT_STREQ(Func("123?" , 'z'), nullptr); |
136 | } |
137 | |
138 | void shouldFindLastOfDuplicates() { |
139 | // '1' is duplicated in the string, but it should find the last copy. |
140 | ASSERT_STREQ(Func("abc1def1ghi" , '1'), "1ghi" ); |
141 | |
142 | const char *dups = "XXXXX" ; |
143 | // Should return the last occurrence of 'X'. |
144 | ASSERT_STREQ(Func(dups, 'X'), "X" ); |
145 | } |
146 | |
147 | void emptyStringShouldOnlyMatchNullTerminator() { |
148 | // Null terminator should match. |
149 | ASSERT_STREQ(Func("" , '\0'), "" ); |
150 | // All other characters should not match. |
151 | ASSERT_STREQ(Func("" , 'A'), nullptr); |
152 | ASSERT_STREQ(Func("" , '2'), nullptr); |
153 | ASSERT_STREQ(Func("" , '*'), nullptr); |
154 | } |
155 | }; |
156 | |
157 | #define STRCHR_TEST(name, func) \ |
158 | using LlvmLibc##name##Test = StrchrTest<func>; \ |
159 | TEST_F(LlvmLibc##name##Test, FindsFirstCharacter) { findsFirstCharacter(); } \ |
160 | TEST_F(LlvmLibc##name##Test, FindsMiddleCharacter) { \ |
161 | findsMiddleCharacter(); \ |
162 | } \ |
163 | TEST_F(LlvmLibc##name##Test, FindsLastCharacterThatIsNotNullTerminator) { \ |
164 | findsLastCharacterThatIsNotNullTerminator(); \ |
165 | } \ |
166 | TEST_F(LlvmLibc##name##Test, FindsNullTerminator) { findsNullTerminator(); } \ |
167 | TEST_F(LlvmLibc##name##Test, CharacterNotWithinStringShouldReturnNullptr) { \ |
168 | characterNotWithinStringShouldReturnNullptr(); \ |
169 | } \ |
170 | TEST_F(LlvmLibc##name##Test, TheSourceShouldNotChange) { \ |
171 | theSourceShouldNotChange(); \ |
172 | } \ |
173 | TEST_F(LlvmLibc##name##Test, ShouldFindFirstOfDuplicates) { \ |
174 | shouldFindFirstOfDuplicates(); \ |
175 | } \ |
176 | TEST_F(LlvmLibc##name##Test, EmptyStringShouldOnlyMatchNullTerminator) { \ |
177 | emptyStringShouldOnlyMatchNullTerminator(); \ |
178 | } |
179 | |
180 | #define STRRCHR_TEST(name, func) \ |
181 | using LlvmLibc##name##Test = StrrchrTest<func>; \ |
182 | TEST_F(LlvmLibc##name##Test, FindsFirstCharacter) { findsFirstCharacter(); } \ |
183 | TEST_F(LlvmLibc##name##Test, FindsMiddleCharacter) { \ |
184 | findsMiddleCharacter(); \ |
185 | } \ |
186 | TEST_F(LlvmLibc##name##Test, FindsLastCharacterThatIsNotNullTerminator) { \ |
187 | findsLastCharacterThatIsNotNullTerminator(); \ |
188 | } \ |
189 | TEST_F(LlvmLibc##name##Test, FindsNullTerminator) { findsNullTerminator(); } \ |
190 | TEST_F(LlvmLibc##name##Test, FindsLastBehindFirstNullTerminator) { \ |
191 | findsLastBehindFirstNullTerminator(); \ |
192 | } \ |
193 | TEST_F(LlvmLibc##name##Test, CharacterNotWithinStringShouldReturnNullptr) { \ |
194 | characterNotWithinStringShouldReturnNullptr(); \ |
195 | } \ |
196 | TEST_F(LlvmLibc##name##Test, ShouldFindLastOfDuplicates) { \ |
197 | shouldFindLastOfDuplicates(); \ |
198 | } \ |
199 | TEST_F(LlvmLibc##name##Test, EmptyStringShouldOnlyMatchNullTerminator) { \ |
200 | emptyStringShouldOnlyMatchNullTerminator(); \ |
201 | } |
202 | |