aboutsummaryrefslogtreecommitdiff
path: root/libc/test/src/string/strtok_r_test.cpp
blob: fdc27bae23c975781d5518f4ce3018b718e1f046 (plain)
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
//===-- Unittests for strtok_r -------------------------------------------===//
//
// 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/strtok_r.h"
#include "test/UnitTest/Test.h"

TEST(LlvmLibcStrTokReentrantTest, NoTokenFound) {
  { // Empty source and delimiter string.
    char empty[] = "";
    char *reserve = nullptr;
    ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(empty, "", &reserve), nullptr);
    // Another call to ensure that 'reserve' is not in a bad state.
    ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(empty, "", &reserve), nullptr);
    ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, "", &reserve), nullptr);
  }
  { // Empty source and single character delimiter string.
    char empty[] = "";
    char *reserve = nullptr;
    ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(empty, "_", &reserve), nullptr);
    // Another call to ensure that 'reserve' is not in a bad state.
    ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(empty, "_", &reserve), nullptr);
    ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, "_", &reserve), nullptr);
  }
  { // Same character source and delimiter string.
    char single[] = "_";
    char *reserve = nullptr;
    ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(single, "_", &reserve), nullptr);
    // Another call to ensure that 'reserve' is not in a bad state.
    ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(single, "_", &reserve), nullptr);
    ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, "_", &reserve), nullptr);
  }
  { // Multiple character source and single character delimiter string.
    char multiple[] = "1,2";
    char *reserve = nullptr;
    ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(multiple, ":", &reserve), "1,2");
    // Another call to ensure that 'reserve' is not in a bad state.
    ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(multiple, ":", &reserve), "1,2");
    ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, ":", &reserve), nullptr);
  }
}

TEST(LlvmLibcStrTokReentrantTest, DelimiterAsFirstCharacterShouldBeIgnored) {
  char src[] = ".123";
  char *reserve = nullptr;
  ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ".", &reserve), "123");
  // Another call to ensure that 'reserve' is not in a bad state.
  ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ".", &reserve), "123");
  ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, ".", &reserve), nullptr);
}

TEST(LlvmLibcStrTokReentrantTest, DelimiterIsMiddleCharacter) {
  char src[] = "12,34";
  char *reserve = nullptr;
  ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ",", &reserve), "12");
  // Another call to ensure that 'reserve' is not in a bad state.
  ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ",", &reserve), "12");
  ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, ",", &reserve), nullptr);
}

TEST(LlvmLibcStrTokReentrantTest, DelimiterAsLastCharacterShouldBeIgnored) {
  char src[] = "1234:";
  char *reserve = nullptr;
  ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ":", &reserve), "1234");
  // Another call to ensure that 'reserve' is not in a bad state.
  ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ":", &reserve), "1234");
  ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, ":", &reserve), nullptr);
}

TEST(LlvmLibcStrTokReentrantTest, ShouldNotGoPastNullTerminator) {
  char src[] = {'1', '2', '\0', ',', '3'};
  char *reserve = nullptr;
  ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ",", &reserve), "12");
  // Another call to ensure that 'reserve' is not in a bad state.
  ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ",", &reserve), "12");
  ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(nullptr, ",", &reserve), nullptr);
}

TEST(LlvmLibcStrTokReentrantTest,
     ShouldReturnNullptrWhenBothSrcAndSaveptrAreNull) {
  char *src = nullptr;
  char *reserve = nullptr;
  // Ensure that instead of crashing if src and reserve are null, nullptr is
  // returned
  ASSERT_STREQ(LIBC_NAMESPACE::strtok_r(src, ",", &reserve), nullptr);
  // And that neither src nor reserve are changed when that happens
  ASSERT_STREQ(src, nullptr);
  ASSERT_STREQ(reserve, nullptr);
}

TEST(LlvmLibcStrTokReentrantTest,
     SubsequentCallsShouldFindFollowingDelimiters) {
  char src[] = "12,34.56";
  char *reserve = nullptr;
  char *token = LIBC_NAMESPACE::strtok_r(src, ",.", &reserve);
  ASSERT_STREQ(token, "12");
  token = LIBC_NAMESPACE::strtok_r(nullptr, ",.", &reserve);
  ASSERT_STREQ(token, "34");
  token = LIBC_NAMESPACE::strtok_r(nullptr, ",.", &reserve);
  ASSERT_STREQ(token, "56");
  token = LIBC_NAMESPACE::strtok_r(nullptr, "_:,_", &reserve);
  ASSERT_STREQ(token, nullptr);
  // Subsequent calls after hitting the end of the string should also return
  // nullptr.
  token = LIBC_NAMESPACE::strtok_r(nullptr, "_:,_", &reserve);
  ASSERT_STREQ(token, nullptr);
}

TEST(LlvmLibcStrTokReentrantTest, DelimitersShouldNotBeIncludedInToken) {
  char src[] = "__ab__:_cd__:__ef__:__";
  char *reserve = nullptr;
  char *token = LIBC_NAMESPACE::strtok_r(src, "_:", &reserve);
  ASSERT_STREQ(token, "ab");
  token = LIBC_NAMESPACE::strtok_r(nullptr, ":_", &reserve);
  ASSERT_STREQ(token, "cd");
  token = LIBC_NAMESPACE::strtok_r(nullptr, "_:,", &reserve);
  ASSERT_STREQ(token, "ef");
  token = LIBC_NAMESPACE::strtok_r(nullptr, "_:,_", &reserve);
  ASSERT_STREQ(token, nullptr);
}