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
11template <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
85template <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

source code of libc/test/src/string/StrchrTest.h