xref: /llvm-project/libc/test/src/string/strtok_r_test.cpp (revision b6bc9d72f65a5086f310f321e969d96e9a559e75)
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 
TEST(LlvmLibcStrTokReentrantTest,NoTokenFound)12 TEST(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 
TEST(LlvmLibcStrTokReentrantTest,DelimiterAsFirstCharacterShouldBeIgnored)47 TEST(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 
TEST(LlvmLibcStrTokReentrantTest,DelimiterIsMiddleCharacter)56 TEST(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 
TEST(LlvmLibcStrTokReentrantTest,DelimiterAsLastCharacterShouldBeIgnored)65 TEST(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 
TEST(LlvmLibcStrTokReentrantTest,ShouldNotGoPastNullTerminator)74 TEST(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 
TEST(LlvmLibcStrTokReentrantTest,ShouldReturnNullptrWhenBothSrcAndSaveptrAreNull)83 TEST(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 
TEST(LlvmLibcStrTokReentrantTest,SubsequentCallsShouldFindFollowingDelimiters)95 TEST(LlvmLibcStrTokReentrantTest,
96      SubsequentCallsShouldFindFollowingDelimiters) {
97   char src[] = "12,34.56";
98   char *reserve = nullptr;
99   char *token = LIBC_NAMESPACE::strtok_r(src, ",.", &reserve);
100   ASSERT_STREQ(token, "12");
101   token = LIBC_NAMESPACE::strtok_r(nullptr, ",.", &reserve);
102   ASSERT_STREQ(token, "34");
103   token = LIBC_NAMESPACE::strtok_r(nullptr, ",.", &reserve);
104   ASSERT_STREQ(token, "56");
105   token = LIBC_NAMESPACE::strtok_r(nullptr, "_:,_", &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(nullptr, "_:,_", &reserve);
110   ASSERT_STREQ(token, nullptr);
111 }
112 
TEST(LlvmLibcStrTokReentrantTest,DelimitersShouldNotBeIncludedInToken)113 TEST(LlvmLibcStrTokReentrantTest, DelimitersShouldNotBeIncludedInToken) {
114   char src[] = "__ab__:_cd__:__ef__:__";
115   char *reserve = nullptr;
116   char *token = LIBC_NAMESPACE::strtok_r(src, "_:", &reserve);
117   ASSERT_STREQ(token, "ab");
118   token = LIBC_NAMESPACE::strtok_r(nullptr, ":_", &reserve);
119   ASSERT_STREQ(token, "cd");
120   token = LIBC_NAMESPACE::strtok_r(nullptr, "_:,", &reserve);
121   ASSERT_STREQ(token, "ef");
122   token = LIBC_NAMESPACE::strtok_r(nullptr, "_:,_", &reserve);
123   ASSERT_STREQ(token, nullptr);
124 }
125