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 
12 TEST(LlvmLibcStrTokReentrantTest, 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 
47 TEST(LlvmLibcStrTokReentrantTest, 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 
56 TEST(LlvmLibcStrTokReentrantTest, 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 
65 TEST(LlvmLibcStrTokReentrantTest, 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 
74 TEST(LlvmLibcStrTokReentrantTest, 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 
83 TEST(LlvmLibcStrTokReentrantTest,
84      SubsequentCallsShouldFindFollowingDelimiters) {
85   char src[] = "12,34.56";
86   char *reserve = nullptr;
87   char *token = __llvm_libc::strtok_r(src, ",.", &reserve);
88   ASSERT_STREQ(token, "12");
89   token = __llvm_libc::strtok_r(nullptr, ",.", &reserve);
90   ASSERT_STREQ(token, "34");
91   token = __llvm_libc::strtok_r(nullptr, ",.", &reserve);
92   ASSERT_STREQ(token, "56");
93   token = __llvm_libc::strtok_r(nullptr, "_:,_", &reserve);
94   ASSERT_STREQ(token, nullptr);
95   // Subsequent calls after hitting the end of the string should also return
96   // nullptr.
97   token = __llvm_libc::strtok_r(nullptr, "_:,_", &reserve);
98   ASSERT_STREQ(token, nullptr);
99 }
100 
101 TEST(LlvmLibcStrTokReentrantTest, DelimitersShouldNotBeIncludedInToken) {
102   char src[] = "__ab__:_cd__:__ef__:__";
103   char *reserve = nullptr;
104   char *token = __llvm_libc::strtok_r(src, "_:", &reserve);
105   ASSERT_STREQ(token, "ab");
106   token = __llvm_libc::strtok_r(nullptr, ":_", &reserve);
107   ASSERT_STREQ(token, "cd");
108   token = __llvm_libc::strtok_r(nullptr, "_:,", &reserve);
109   ASSERT_STREQ(token, "ef");
110   token = __llvm_libc::strtok_r(nullptr, "_:,_", &reserve);
111   ASSERT_STREQ(token, nullptr);
112 }
113