1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
//===-- Unittests for memchr ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "src/string/memchr.h"
#include <stddef.h>
#include "hdr/signal_macros.h"
#include "test/UnitTest/Test.h"
namespace {
// A helper function that calls memchr and abstracts away the explicit cast for
// readability purposes.
const char *call_memchr(const void *src, int c, size_t size) {
return reinterpret_cast<const char *>(LIBC_NAMESPACE::memchr(src, c, size));
}
TEST(LlvmLibcMemChrTest, FindsCharacterAfterNullTerminator) {
// memchr should continue searching after a null terminator.
const size_t size = 5;
const unsigned char src[size] = {'a', '\0', 'b', 'c', '\0'};
// Should return 'b', 'c', '\0' even when after null terminator.
ASSERT_STREQ(call_memchr(src, 'b', size), "bc");
}
TEST(LlvmLibcMemChrTest, FindsCharacterInNonNullTerminatedCollection) {
const size_t size = 3;
const unsigned char src[size] = {'a', 'b', 'c'};
// Should return 'b', 'c'.
const char *ret = call_memchr(src, 'b', size);
ASSERT_EQ(ret[0], 'b');
ASSERT_EQ(ret[1], 'c');
}
TEST(LlvmLibcMemChrTest, FindsFirstCharacter) {
const size_t size = 6;
const unsigned char src[size] = {'a', 'b', 'c', 'd', 'e', '\0'};
// Should return original array since 'a' is the first character.
ASSERT_STREQ(call_memchr(src, 'a', size), "abcde");
}
TEST(LlvmLibcMemChrTest, FindsMiddleCharacter) {
const size_t size = 6;
const unsigned char src[size] = {'a', 'b', 'c', 'd', 'e', '\0'};
// Should return characters after (and including) 'c'.
ASSERT_STREQ(call_memchr(src, 'c', size), "cde");
}
TEST(LlvmLibcMemChrTest, FindsLastCharacterThatIsNotNullTerminator) {
const size_t size = 6;
const unsigned char src[size] = {'a', 'b', 'c', 'd', 'e', '\0'};
// Should return 'e' and null-terminator.
ASSERT_STREQ(call_memchr(src, 'e', size), "e");
}
TEST(LlvmLibcMemChrTest, FindsNullTerminator) {
const size_t size = 6;
const unsigned char src[size] = {'a', 'b', 'c', 'd', 'e', '\0'};
// Should return null terminator.
ASSERT_STREQ(call_memchr(src, '\0', size), "");
}
TEST(LlvmLibcMemChrTest, CharacterNotWithinStringShouldReturnNullptr) {
const size_t size = 4;
const unsigned char src[size] = {'1', '2', '3', '?'};
// Since 'z' is not within 'characters', should return nullptr.
ASSERT_STREQ(call_memchr(src, 'z', size), nullptr);
}
TEST(LlvmLibcMemChrTest, CharacterNotWithinSizeShouldReturnNullptr) {
const unsigned char src[5] = {'1', '2', '3', '4', '\0'};
// Since '4' is not the first or second character, this should return nullptr.
const size_t size = 2;
ASSERT_STREQ(call_memchr(src, '4', size), nullptr);
}
TEST(LlvmLibcMemChrTest, TheSourceShouldNotChange) {
const size_t size = 6;
const unsigned char src[size] = {'a', 'b', 'c', 'd', 'e', '\0'};
const char *src_copy = reinterpret_cast<const char *>(src);
// When the character is found, the source string should not change.
LIBC_NAMESPACE::memchr(src, 'd', size);
ASSERT_STREQ(reinterpret_cast<const char *>(src), src_copy);
// Same case for when the character is not found.
LIBC_NAMESPACE::memchr(src, 'z', size);
ASSERT_STREQ(reinterpret_cast<const char *>(src), src_copy);
}
TEST(LlvmLibcMemChrTest, ShouldFindFirstOfDuplicates) {
const size_t size = 12; // 11 characters + null terminator.
const char *dups = "abc1def1ghi";
// 1 is duplicated in 'dups', but it should find the first copy.
ASSERT_STREQ(call_memchr(dups, '1', size), "1def1ghi");
}
TEST(LlvmLibcMemChrTest, EmptyStringShouldOnlyMatchNullTerminator) {
const size_t size = 1; // Null terminator.
const char *empty_string = "";
// Null terminator should match.
ASSERT_STREQ(call_memchr(empty_string, '\0', size), "");
// All other characters should not match.
ASSERT_STREQ(call_memchr(empty_string, 'A', size), nullptr);
ASSERT_STREQ(call_memchr(empty_string, '9', size), nullptr);
ASSERT_STREQ(call_memchr(empty_string, '?', size), nullptr);
}
TEST(LlvmLibcMemChrTest, SingleRepeatedCharacterShouldReturnFirst) {
const char *dups = "XXXXX";
const size_t size = 6; // 5 characters + null terminator.
// Should return original string since X is first character.
ASSERT_STREQ(call_memchr(dups, 'X', size), dups);
}
TEST(LlvmLibcMemChrTest, SignedCharacterFound) {
char c = -1;
const size_t size = 1;
char src[size] = {c};
const char *actual = call_memchr(src, c, size);
// Should find the first character 'c'.
ASSERT_EQ(actual[0], c);
}
#if defined(LIBC_ADD_NULL_CHECKS)
TEST(LlvmLibcMemChrTest, CrashOnNullPtr) {
ASSERT_DEATH([]() { LIBC_NAMESPACE::memchr(nullptr, 1, 1); },
WITH_SIGNAL(-1));
}
#endif // defined(LIBC_ADD_NULL_CHECKS)
} // namespace
|