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