1//===-- Unittests for strtok_r -------------------------------------------===//
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 "src/string/strtok_r.h"
10#include "test/UnitTest/Test.h"
11
12TEST(LlvmLibcStrTokReentrantTest, NoTokenFound) {
13 { // Empty source and delimiter string.
14 char empty[] = "";
15 char *reserve = nullptr;
16 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(empty, "", &reserve), nullptr);
17 // Another call to ensure that 'reserve' is not in a bad state.
18 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(empty, "", &reserve), nullptr);
19 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, "", &reserve), nullptr);
20 }
21 { // Empty source and single character delimiter string.
22 char empty[] = "";
23 char *reserve = nullptr;
24 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(empty, "_", &reserve), nullptr);
25 // Another call to ensure that 'reserve' is not in a bad state.
26 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(empty, "_", &reserve), nullptr);
27 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, "_", &reserve), nullptr);
28 }
29 { // Same character source and delimiter string.
30 char single[] = "_";
31 char *reserve = nullptr;
32 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(single, "_", &reserve), nullptr);
33 // Another call to ensure that 'reserve' is not in a bad state.
34 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(single, "_", &reserve), nullptr);
35 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, "_", &reserve), nullptr);
36 }
37 { // Multiple character source and single character delimiter string.
38 char multiple[] = "1,2";
39 char *reserve = nullptr;
40 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(multiple, ":", &reserve), "1,2");
41 // Another call to ensure that 'reserve' is not in a bad state.
42 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(multiple, ":", &reserve), "1,2");
43 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, ":", &reserve), nullptr);
44 }
45}
46
47TEST(LlvmLibcStrTokReentrantTest, DelimiterAsFirstCharacterShouldBeIgnored) {
48 char src[] = ".123";
49 char *reserve = nullptr;
50 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ".", &reserve), "123");
51 // Another call to ensure that 'reserve' is not in a bad state.
52 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ".", &reserve), "123");
53 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, ".", &reserve), nullptr);
54}
55
56TEST(LlvmLibcStrTokReentrantTest, DelimiterIsMiddleCharacter) {
57 char src[] = "12,34";
58 char *reserve = nullptr;
59 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ",", &reserve), "12");
60 // Another call to ensure that 'reserve' is not in a bad state.
61 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ",", &reserve), "12");
62 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, ",", &reserve), nullptr);
63}
64
65TEST(LlvmLibcStrTokReentrantTest, DelimiterAsLastCharacterShouldBeIgnored) {
66 char src[] = "1234:";
67 char *reserve = nullptr;
68 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ":", &reserve), "1234");
69 // Another call to ensure that 'reserve' is not in a bad state.
70 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ":", &reserve), "1234");
71 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, ":", &reserve), nullptr);
72}
73
74TEST(LlvmLibcStrTokReentrantTest, ShouldNotGoPastNullTerminator) {
75 char src[] = {'1', '2', '\0', ',', '3'};
76 char *reserve = nullptr;
77 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ",", &reserve), "12");
78 // Another call to ensure that 'reserve' is not in a bad state.
79 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ",", &reserve), "12");
80 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, ",", &reserve), nullptr);
81}
82
83TEST(LlvmLibcStrTokReentrantTest,
84 ShouldReturnNullptrWhenBothSrcAndSaveptrAreNull) {
85 char *src = nullptr;
86 char *reserve = nullptr;
87 // Ensure that instead of crashing if src and reserve are null, nullptr is
88 // returned
89 ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ",", &reserve), nullptr);
90 // And that neither src nor reserve are changed when that happens
91 ASSERT_STREQ(src, nullptr);
92 ASSERT_STREQ(reserve, nullptr);
93}
94
95TEST(LlvmLibcStrTokReentrantTest,
96 SubsequentCallsShouldFindFollowingDelimiters) {
97 char src[] = "12,34.56";
98 char *reserve = nullptr;
99 char *token = LIBC_NAMESPACE::strtok_r(src, delimiter_string: ",.", saveptr: &reserve);
100 ASSERT_STREQ(token, "12");
101 token = LIBC_NAMESPACE::strtok_r(src: nullptr, delimiter_string: ",.", saveptr: &reserve);
102 ASSERT_STREQ(token, "34");
103 token = LIBC_NAMESPACE::strtok_r(src: nullptr, delimiter_string: ",.", saveptr: &reserve);
104 ASSERT_STREQ(token, "56");
105 token = LIBC_NAMESPACE::strtok_r(src: nullptr, delimiter_string: "_:,_", saveptr: &reserve);
106 ASSERT_STREQ(token, nullptr);
107 // Subsequent calls after hitting the end of the string should also return
108 // nullptr.
109 token = LIBC_NAMESPACE::strtok_r(src: nullptr, delimiter_string: "_:,_", saveptr: &reserve);
110 ASSERT_STREQ(token, nullptr);
111}
112
113TEST(LlvmLibcStrTokReentrantTest, DelimitersShouldNotBeIncludedInToken) {
114 char src[] = "__ab__:_cd__:__ef__:__";
115 char *reserve = nullptr;
116 char *token = LIBC_NAMESPACE::strtok_r(src, delimiter_string: "_:", saveptr: &reserve);
117 ASSERT_STREQ(token, "ab");
118 token = LIBC_NAMESPACE::strtok_r(src: nullptr, delimiter_string: ":_", saveptr: &reserve);
119 ASSERT_STREQ(token, "cd");
120 token = LIBC_NAMESPACE::strtok_r(src: nullptr, delimiter_string: "_:,", saveptr: &reserve);
121 ASSERT_STREQ(token, "ef");
122 token = LIBC_NAMESPACE::strtok_r(src: nullptr, delimiter_string: "_:,_", saveptr: &reserve);
123 ASSERT_STREQ(token, nullptr);
124}
125

source code of libc/test/src/string/strtok_r_test.cpp