1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2016 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17
18#include <gtest/gtest.h>
19#include <platform/sized_buffer.h>
20
21#include <unordered_set>
22
23template <size_t N>
24cb::const_char_buffer make_ccb(const char (&c)[N]) {
25    return {c, N - 1};
26}
27
28TEST(SizedBufferTest, Comparison) {
29    auto A = "abc"_ccb;
30    auto B = "def"_ccb;
31
32    // Technically all these could be done through the appropriate
33    // EXPECT_* macros but I feel it's more explicit to invoke the
34    // operator overloads directly.
35
36    EXPECT_TRUE(A == A);
37    EXPECT_TRUE(A >= A);
38    EXPECT_TRUE(A <= A);
39    EXPECT_TRUE(B == B);
40    EXPECT_TRUE(B >= B);
41    EXPECT_TRUE(B <= B);
42
43    EXPECT_FALSE(A == B);
44    EXPECT_TRUE(A != B);
45    EXPECT_TRUE(A < B);
46    EXPECT_TRUE(A <= B);
47    EXPECT_FALSE(A >= B);
48    EXPECT_FALSE(A > B);
49
50    EXPECT_FALSE(B == A);
51    EXPECT_TRUE(B != A);
52    EXPECT_FALSE(B < A);
53    EXPECT_FALSE(B <= A);
54    EXPECT_TRUE(B >= A);
55    EXPECT_TRUE(B > A);
56
57    auto C = make_ccb("abc");
58    auto D = make_ccb("abcd");
59
60    EXPECT_FALSE(C == D);
61    EXPECT_TRUE(C != D);
62    EXPECT_TRUE(D >= C);
63    EXPECT_TRUE(D > C);
64    EXPECT_FALSE(D <= C);
65    EXPECT_FALSE(D < C);
66
67    // Empty buffers
68
69    auto E = make_ccb("");
70    cb::const_char_buffer F;
71    EXPECT_TRUE(E == F);
72    EXPECT_FALSE(F == C);
73}
74
75TEST(SizedBufferTest, SubStr) {
76    auto A = make_ccb("Hello, World!");
77
78    EXPECT_EQ(make_ccb("Hello, World!"), A.substr(0));
79    EXPECT_EQ(make_ccb("Hello"), A.substr(0, 5));
80    EXPECT_EQ(make_ccb("World"), A.substr(7, 5));
81    EXPECT_EQ(make_ccb("World!"), A.substr(7, 50));
82    EXPECT_EQ(make_ccb("World!"), A.substr(7));
83    EXPECT_EQ(make_ccb(""), A.substr(0, 0));
84
85    EXPECT_THROW(A.substr(A.size() + 1), std::out_of_range);
86    EXPECT_THROW(A.substr(50), std::out_of_range);
87
88    cb::const_char_buffer B;
89    EXPECT_EQ(B, B.substr(0, 50));
90    EXPECT_THROW(A.substr(50), std::out_of_range);
91}
92
93TEST(SizedBufferTest, Access) {
94    const char s[] = "Hello, World!";
95    auto A = make_ccb(s);
96
97    EXPECT_EQ(s, A.data());
98    EXPECT_EQ(s, A.begin());
99    EXPECT_EQ(s, A.cbegin());
100    EXPECT_EQ(&s[sizeof(s) - 1], A.end());
101    EXPECT_EQ(&s[sizeof(s) - 1], A.cend());
102
103    EXPECT_EQ('H', A.front());
104    EXPECT_EQ('!', A.back());
105
106    for (size_t i = 0; i < sizeof(s) - 1; ++i) {
107        EXPECT_EQ(s[i], A[i]);
108        EXPECT_EQ(s[i], A.at(i));
109    }
110    EXPECT_THROW(A.at(A.size()), std::out_of_range);
111
112    cb::const_char_buffer B;
113    EXPECT_THROW(B.at(0), std::out_of_range);
114}
115
116TEST(SizedBufferTest, Capacity) {
117    auto A = make_ccb("Hello, World!");
118    EXPECT_EQ(13u, A.size());
119    EXPECT_FALSE(A.empty());
120    EXPECT_TRUE(make_ccb("").empty());
121}
122
123TEST(SizedBufferTest, Find) {
124    auto A = make_ccb("Hello, World!");
125    EXPECT_EQ(0u, A.find(make_ccb("Hello")));
126    EXPECT_EQ(7u, A.find(make_ccb("World!")));
127    EXPECT_EQ(A.npos, A.find(make_ccb("Trond!")));
128    EXPECT_EQ(0u, A.find(make_ccb("")));
129
130    auto R = make_ccb("RepeatRepeatRepeat");
131    EXPECT_EQ(0u, R.find(make_ccb("Repeat")));
132    EXPECT_EQ(6u, R.find(make_ccb("Repeat"), 1));
133    EXPECT_EQ(12u, R.find(make_ccb("Repeat"), 7));
134
135    cb::const_char_buffer B;
136    EXPECT_EQ(B.npos, B.find(make_ccb("")));
137}
138
139TEST(SizedBufferTest, FindFirstOf) {
140    auto A = make_ccb("Hello, World!");
141    EXPECT_EQ(0u, A.find_first_of(make_ccb("Hello")));
142    EXPECT_EQ(1u, A.find_first_of(make_ccb("ello")));
143    EXPECT_EQ(2u, A.find_first_of(make_ccb("llo")));
144    EXPECT_EQ(2u, A.find_first_of(make_ccb("lo")));
145    EXPECT_EQ(4u, A.find_first_of(make_ccb("o")));
146    EXPECT_EQ(8u, A.find_first_of(make_ccb("o"), 6));
147    EXPECT_EQ(12u, A.find_first_of(make_ccb("!")));
148    EXPECT_EQ(A.npos, A.find_first_of(make_ccb("?")));
149    EXPECT_EQ(A.npos, A.find_first_of(make_ccb("")));
150    EXPECT_EQ(A.npos, A.find_first_of(make_ccb("H"), 5));
151
152    cb::const_char_buffer B;
153    EXPECT_EQ(B.npos, B.find_first_of(make_ccb("")));
154    EXPECT_EQ(B.npos, B.find_first_of(make_ccb("abcdef"), 1));
155    EXPECT_EQ(B.npos, B.find_first_of(make_ccb("?")));
156}
157
158// Smoke test that hashing and comparison works well enough for unordered_set
159TEST(SizedBufferTest, Set) {
160    std::unordered_set<cb::const_char_buffer> s;
161
162    auto ret = s.insert(make_ccb("Hello, World!"));
163    EXPECT_TRUE(ret.second);
164
165    ret = s.insert(make_ccb("Hello, World"));
166    EXPECT_TRUE(ret.second);
167
168    ret = s.insert(make_ccb("Hello"));
169    EXPECT_TRUE(ret.second);
170
171    ret = s.insert(make_ccb("World"));
172    EXPECT_TRUE(ret.second);
173
174    ret = s.insert(make_ccb("Hello, World!"));
175    EXPECT_FALSE(ret.second);
176}
177
178TEST(SizedBufferTest, FromString) {
179    std::string str = "Hello, World";
180    cb::const_char_buffer ccb = str;
181    cb::char_buffer cb = str;
182    EXPECT_EQ(str.data(), ccb.data());
183    EXPECT_EQ(str.size(), ccb.size());
184    EXPECT_EQ(str.data(), cb.data());
185    EXPECT_EQ(str.size(), cb.size());
186}
187
188TEST(SizedBufferTest, FromVector) {
189    std::string str = "Hello, World";
190    std::vector<char> vec(str.begin(), str.end());
191    cb::const_char_buffer ccb = vec;
192    cb::char_buffer cb = vec;
193
194    EXPECT_EQ(vec.data(), ccb.data());
195    EXPECT_EQ(vec.size(), ccb.size());
196    EXPECT_EQ(vec.data(), cb.data());
197    EXPECT_EQ(vec.size(), cb.size());
198}
199
200TEST(SizedBufferTest, ToConst) {
201    char str[] = "Hello, World!";
202    cb::char_buffer cb{str, sizeof(str) - 1};
203    cb::const_char_buffer ccb = cb;
204
205    EXPECT_EQ(ccb.data(), cb.data());
206    EXPECT_EQ(ccb.size(), cb.size());
207}
208
209TEST(SizedBufferTest, cString1) {
210    const char* cStr = "Hello, World!";
211    cb::const_char_buffer ccb(cStr);
212
213    EXPECT_STREQ("Hello, World!", ccb.data());
214    EXPECT_EQ(std::strlen("Hello, World!"), ccb.size());
215
216    auto str = cb::to_string(ccb);
217    EXPECT_EQ(0, str.compare(ccb.data()));
218    EXPECT_EQ(ccb.size(), str.size());
219}
220
221TEST(SizedBufferTest, cString2) {
222    const char* cStr = "Hello, World!";
223    std::string str(cStr);
224    cb::const_char_buffer ccb1(str);
225    cb::const_char_buffer ccb2(cStr);
226    EXPECT_EQ(ccb1, ccb2);
227}
228