1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #include "mongo/base/data_builder.h"
32 #include "mongo/base/data_type_terminated.h"
33 
34 #include "mongo/platform/endian.h"
35 #include "mongo/unittest/unittest.h"
36 
37 namespace mongo {
38 
39 namespace {
40 /**
41  * Helper type for writeAndAdvance in tests
42  */
43 template <std::size_t bytes>
44 struct NByteStruct {
45     NByteStruct() = default;
46     char buf[bytes] = {};
47 };
48 
49 }  // namespace
50 
TEST(DataBuilder,Basic)51 TEST(DataBuilder, Basic) {
52     DataBuilder db(1);
53 
54     ASSERT_EQUALS(true, db.writeAndAdvance<uint16_t>(1).isOK());
55     ASSERT_EQUALS(true, db.writeAndAdvance<LittleEndian<uint32_t>>(2).isOK());
56     ASSERT_EQUALS(true, db.writeAndAdvance<BigEndian<uint64_t>>(3).isOK());
57 
58     ASSERT_EQUALS(18u, db.capacity());
59     ASSERT_EQUALS(14u, db.size());
60 
61     db.resize(14u);
62     ASSERT_EQUALS(14u, db.capacity());
63     ASSERT_EQUALS(14u, db.size());
64 
65     db.reserve(2u);
66     ASSERT_EQUALS(21u, db.capacity());
67     ASSERT_EQUALS(14u, db.size());
68 
69     ConstDataRangeCursor cdrc = db.getCursor();
70 
71     ASSERT_EQUALS(static_cast<uint16_t>(1), cdrc.readAndAdvance<uint16_t>().getValue());
72     ASSERT_EQUALS(static_cast<uint32_t>(2),
73                   cdrc.readAndAdvance<LittleEndian<uint32_t>>().getValue());
74     ASSERT_EQUALS(static_cast<uint64_t>(3), cdrc.readAndAdvance<BigEndian<uint64_t>>().getValue());
75     ASSERT_EQUALS(false, cdrc.readAndAdvance<char>().isOK());
76 }
77 
TEST(DataBuilder,ResizeDown)78 TEST(DataBuilder, ResizeDown) {
79     DataBuilder db(1);
80 
81     ASSERT_EQUALS(true, db.writeAndAdvance<uint16_t>(1).isOK());
82     ASSERT_EQUALS(true, db.writeAndAdvance<uint64_t>(2).isOK());
83 
84     db.resize(2u);
85     ASSERT_EQUALS(2u, db.capacity());
86     ASSERT_EQUALS(2u, db.size());
87 
88     ConstDataRangeCursor cdrc = db.getCursor();
89 
90     ASSERT_EQUALS(static_cast<uint16_t>(1), cdrc.readAndAdvance<uint16_t>().getValue());
91     ASSERT_EQUALS(false, cdrc.readAndAdvance<char>().isOK());
92 }
93 
TEST(DataBuilder,ResizeUp)94 TEST(DataBuilder, ResizeUp) {
95     DataBuilder db(1);
96 
97     ASSERT_EQUALS(true, db.writeAndAdvance<uint16_t>(1).isOK());
98     ASSERT_EQUALS(true, db.writeAndAdvance<uint64_t>(2).isOK());
99 
100     db.resize(64u);
101     ASSERT_EQUALS(64u, db.capacity());
102     ASSERT_EQUALS(10u, db.size());
103 
104     ConstDataRangeCursor cdrc = db.getCursor();
105 
106     ASSERT_EQUALS(static_cast<uint16_t>(1), cdrc.readAndAdvance<uint16_t>().getValue());
107     ASSERT_EQUALS(static_cast<uint64_t>(2), cdrc.readAndAdvance<uint64_t>().getValue());
108     ASSERT_EQUALS(false, cdrc.readAndAdvance<char>().isOK());
109 }
110 
TEST(DataBuilder,Reserve)111 TEST(DataBuilder, Reserve) {
112     DataBuilder db;
113 
114     ASSERT_EQUALS(0u, db.capacity());
115     ASSERT_EQUALS(0u, db.size());
116 
117     // first step up is to 64
118     db.reserve(10);
119     ASSERT_EQUALS(64u, db.capacity());
120     ASSERT_EQUALS(0u, db.size());
121 
122     // reserving less than we have doesn't change anything
123     db.reserve(1);
124     ASSERT_EQUALS(64u, db.capacity());
125     ASSERT_EQUALS(0u, db.size());
126 
127     // next actual step up goes up by x1.5
128     db.reserve(65);
129     ASSERT_EQUALS(96u, db.capacity());
130     ASSERT_EQUALS(0u, db.size());
131 
132     ASSERT_EQUALS(true, db.writeAndAdvance(NByteStruct<90>()).isOK());
133     ASSERT_EQUALS(96u, db.capacity());
134     ASSERT_EQUALS(90u, db.size());
135 
136     // partially satisfiable reserve works
137     db.reserve(7);
138     ASSERT_EQUALS(144u, db.capacity());
139     ASSERT_EQUALS(90u, db.size());
140 }
141 
TEST(DataBuilder,Clear)142 TEST(DataBuilder, Clear) {
143     DataBuilder db(1);
144 
145     ASSERT_EQUALS(true, db.writeAndAdvance<uint16_t>(1).isOK());
146 
147     db.clear();
148     ASSERT_EQUALS(2u, db.capacity());
149     ASSERT_EQUALS(0u, db.size());
150 
151     ConstDataRangeCursor cdrc = db.getCursor();
152     ASSERT_EQUALS(false, cdrc.readAndAdvance<char>().isOK());
153 }
154 
TEST(DataBuilder,Move)155 TEST(DataBuilder, Move) {
156     DataBuilder db(1);
157 
158     ASSERT_EQUALS(true, db.writeAndAdvance<uint16_t>(1).isOK());
159 
160     auto db2 = DataBuilder(std::move(db));
161 
162     ConstDataRangeCursor cdrc = db2.getCursor();
163 
164     ASSERT_EQUALS(static_cast<uint16_t>(1), cdrc.readAndAdvance<uint16_t>().getValue());
165     ASSERT_EQUALS(2u, db2.capacity());
166     ASSERT_EQUALS(2u, db2.size());
167 
168     ASSERT_EQUALS(0u, db.capacity());
169     ASSERT_EQUALS(0u, db.size());
170     ASSERT(!db.getCursor().data());
171 }
172 
TEST(DataBuilder,TerminatedStringDatas)173 TEST(DataBuilder, TerminatedStringDatas) {
174     DataBuilder db{10};
175     StringData sample{"abcdefgh"};
176 
177     auto status2 = db.writeAndAdvance<Terminated<'\0', StringData>>(sample);
178     ASSERT_EQUALS(true, status2.isOK());
179 
180     auto status3 = db.writeAndAdvance<Terminated<'\0', StringData>>(sample);
181     ASSERT_EQUALS(true, status3.isOK());
182 }
183 
184 }  // namespace mongo
185