Skip to content

Commit f7e0c52

Browse files
generatedunixname2124183968404147meta-codesync[bot]
authored andcommitted
xplat/ocean/impl/ocean/io/Bitstream.cpp
Reviewed By: hovsepm Differential Revision: D111031766 fbshipit-source-id: 7c0ca48ff728a72de611b0a5324a988db7f4b4fe
1 parent fc6ff68 commit f7e0c52

1 file changed

Lines changed: 269 additions & 0 deletions

File tree

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#include "ocean/io/Bitstream.h"
9+
10+
#ifdef OCEAN_USE_GTEST
11+
12+
#include <gtest/gtest.h>
13+
14+
#include <cstdint>
15+
#include <sstream>
16+
#include <string>
17+
18+
namespace Ocean
19+
{
20+
21+
namespace Test
22+
{
23+
24+
namespace TestIO
25+
{
26+
27+
namespace
28+
{
29+
30+
// Helper: Populate an output stream with a mixed payload and return the
31+
// resulting byte buffer as a string suitable for feeding InputBitstream.
32+
std::string makeMixedPayload()
33+
{
34+
std::ostringstream output;
35+
IO::OutputBitstream out(output);
36+
37+
EXPECT_TRUE(out.write<unsigned int>(0xDEADBEEFu));
38+
EXPECT_TRUE(out.write<int>(-42));
39+
EXPECT_TRUE(out.write<double>(3.1415926535));
40+
EXPECT_TRUE(out.write<std::string>(std::string("hello world")));
41+
EXPECT_TRUE(out.write<std::wstring>(std::wstring(L"wchr")));
42+
43+
return output.str();
44+
}
45+
46+
} // namespace
47+
48+
// InputBitstream <-> OutputBitstream: end-to-end round-trip through a real
49+
// std::stringstream buffer. Exercises typed write + typed read paths across
50+
// the two components with a heterogeneous payload.
51+
TEST(BitstreamIntegrationTest, RoundTripHeterogeneousPayload)
52+
{
53+
std::stringstream stream;
54+
IO::OutputBitstream out(stream);
55+
IO::InputBitstream in(stream);
56+
57+
ASSERT_TRUE(out.write<unsigned int>(0xDEADBEEFu));
58+
ASSERT_TRUE(out.write<int>(-42));
59+
ASSERT_TRUE(out.write<double>(3.1415926535));
60+
ASSERT_TRUE(out.write<std::string>(std::string("hello world")));
61+
ASSERT_TRUE(out.write<std::wstring>(std::wstring(L"wchr")));
62+
63+
unsigned int u = 0u;
64+
int i = 0;
65+
double d = 0.0;
66+
std::string s;
67+
std::wstring w;
68+
69+
ASSERT_TRUE(in.read<unsigned int>(u));
70+
ASSERT_TRUE(in.read<int>(i));
71+
ASSERT_TRUE(in.read<double>(d));
72+
ASSERT_TRUE(in.read<std::string>(s));
73+
ASSERT_TRUE(in.read<std::wstring>(w));
74+
75+
EXPECT_EQ(u, 0xDEADBEEFu);
76+
EXPECT_EQ(i, -42);
77+
EXPECT_DOUBLE_EQ(d, 3.1415926535);
78+
EXPECT_EQ(s, std::string("hello world"));
79+
EXPECT_EQ(w, std::wstring(L"wchr"));
80+
}
81+
82+
// InputBitstream + std::istringstream: size(), position(), setPosition(),
83+
// skip() interact with the underlying std::istream state.
84+
TEST(BitstreamIntegrationTest, PositionSizeSkipAndSetPosition)
85+
{
86+
const std::string payload = makeMixedPayload();
87+
ASSERT_FALSE(payload.empty());
88+
89+
std::istringstream input(payload);
90+
IO::InputBitstream in(input);
91+
92+
const uint64_t total = in.size();
93+
EXPECT_EQ(total, static_cast<uint64_t>(payload.size()));
94+
95+
// Initial position must be zero.
96+
EXPECT_EQ(in.position(), uint64_t(0));
97+
98+
// Read the first 4-byte value and verify position advances accordingly.
99+
unsigned int first = 0u;
100+
ASSERT_TRUE(in.read<unsigned int>(first));
101+
EXPECT_EQ(first, 0xDEADBEEFu);
102+
EXPECT_EQ(in.position(), uint64_t(sizeof(unsigned int)));
103+
104+
// Skipping zero bytes is a no-op and must succeed.
105+
EXPECT_TRUE(in.skip(0));
106+
EXPECT_EQ(in.position(), uint64_t(sizeof(unsigned int)));
107+
108+
// Skip over the int(-42) so the next read is the double.
109+
ASSERT_TRUE(in.skip(sizeof(int)));
110+
double d = 0.0;
111+
ASSERT_TRUE(in.read<double>(d));
112+
EXPECT_DOUBLE_EQ(d, 3.1415926535);
113+
114+
// Rewind and confirm the first value can be re-read.
115+
ASSERT_TRUE(in.setPosition(0));
116+
EXPECT_EQ(in.position(), uint64_t(0));
117+
unsigned int again = 0u;
118+
ASSERT_TRUE(in.read<unsigned int>(again));
119+
EXPECT_EQ(again, 0xDEADBEEFu);
120+
121+
// Seeking beyond end must fail without disturbing readability.
122+
EXPECT_FALSE(in.setPosition(total + 1));
123+
124+
// Skipping to exactly end-of-stream must succeed.
125+
ASSERT_TRUE(in.setPosition(0));
126+
EXPECT_TRUE(in.skip(total));
127+
EXPECT_EQ(in.position(), total);
128+
}
129+
130+
// look<T>() (via ScopedInputBitstream) must NOT advance the underlying
131+
// istream, so a subsequent read yields the same value.
132+
TEST(BitstreamIntegrationTest, LookDoesNotConsume)
133+
{
134+
std::stringstream stream;
135+
IO::OutputBitstream out(stream);
136+
ASSERT_TRUE(out.write<int>(12345));
137+
ASSERT_TRUE(out.write<int>(67890));
138+
139+
IO::InputBitstream in(stream);
140+
141+
int peeked = 0;
142+
ASSERT_TRUE(in.look<int>(peeked));
143+
EXPECT_EQ(peeked, 12345);
144+
EXPECT_EQ(in.position(), uint64_t(0));
145+
146+
int consumed = 0;
147+
ASSERT_TRUE(in.read<int>(consumed));
148+
EXPECT_EQ(consumed, 12345);
149+
EXPECT_EQ(in.position(), uint64_t(sizeof(int)));
150+
151+
int next = 0;
152+
ASSERT_TRUE(in.read<int>(next));
153+
EXPECT_EQ(next, 67890);
154+
}
155+
156+
// readDefault<T>() returns the default value once the stream is exhausted.
157+
// Exercises the failure fallback branch through real stream state.
158+
TEST(BitstreamIntegrationTest, ReadDefaultFallsBackWhenExhausted)
159+
{
160+
std::stringstream stream;
161+
IO::OutputBitstream out(stream);
162+
ASSERT_TRUE(out.write<int>(777));
163+
164+
IO::InputBitstream in(stream);
165+
166+
// First readDefault consumes the written int.
167+
const int firstRead = in.readDefault<int>(-1);
168+
EXPECT_EQ(firstRead, 777);
169+
170+
// Second readDefault has no data — the sentinel default must come back.
171+
const int fallback = in.readDefault<int>(-1);
172+
EXPECT_EQ(fallback, -1);
173+
174+
// Reading past EOF must set the eof flag observable via isEndOfFile().
175+
EXPECT_TRUE(in.isEndOfFile());
176+
}
177+
178+
// reset() must clear EOF state and rewind, allowing subsequent successful
179+
// reads that were previously blocked by the eofbit.
180+
TEST(BitstreamIntegrationTest, ResetClearsEofAndRewinds)
181+
{
182+
std::stringstream stream;
183+
IO::OutputBitstream out(stream);
184+
ASSERT_TRUE(out.write<int>(11));
185+
ASSERT_TRUE(out.write<int>(22));
186+
187+
IO::InputBitstream in(stream);
188+
189+
int a = 0;
190+
int b = 0;
191+
ASSERT_TRUE(in.read<int>(a));
192+
ASSERT_TRUE(in.read<int>(b));
193+
EXPECT_EQ(a, 11);
194+
EXPECT_EQ(b, 22);
195+
196+
// Force EOF by attempting one more read past the end.
197+
int extra = 0;
198+
EXPECT_FALSE(in.read<int>(extra));
199+
EXPECT_TRUE(in.isEndOfFile());
200+
201+
// After reset(), the stream is usable again and reads return the same
202+
// initial values in order.
203+
ASSERT_TRUE(in.reset());
204+
EXPECT_EQ(in.position(), uint64_t(0));
205+
206+
int a2 = 0;
207+
int b2 = 0;
208+
ASSERT_TRUE(in.read<int>(a2));
209+
ASSERT_TRUE(in.read<int>(b2));
210+
EXPECT_EQ(a2, 11);
211+
EXPECT_EQ(b2, 22);
212+
}
213+
214+
// OutputBitstream::write(void*, size) + InputBitstream::read(void*, size)
215+
// combined round-trip of a raw byte buffer, exercising the non-templated
216+
// overloads.
217+
TEST(BitstreamIntegrationTest, RawBufferRoundTrip)
218+
{
219+
const unsigned char pattern[8] = {0x01u, 0x23u, 0x45u, 0x67u,
220+
0x89u, 0xABu, 0xCDu, 0xEFu};
221+
222+
std::stringstream stream;
223+
IO::OutputBitstream out(stream);
224+
225+
// Writing size 0 with any pointer is a no-op and must succeed.
226+
EXPECT_TRUE(out.write(pattern, 0));
227+
228+
ASSERT_TRUE(out.write(pattern, sizeof(pattern)));
229+
EXPECT_EQ(out.size(), uint64_t(sizeof(pattern)));
230+
231+
IO::InputBitstream in(stream);
232+
unsigned char readback[8] = {0u};
233+
234+
// Reading size 0 is a no-op and must succeed without touching state.
235+
EXPECT_TRUE(in.read(readback, 0));
236+
EXPECT_EQ(in.position(), uint64_t(0));
237+
238+
ASSERT_TRUE(in.read(readback, sizeof(readback)));
239+
for (size_t n = 0; n < sizeof(pattern); ++n)
240+
{
241+
EXPECT_EQ(readback[n], pattern[n]) << "mismatch at index " << n;
242+
}
243+
}
244+
245+
// Empty std::string round-trips correctly: the length prefix is written and
246+
// read even though there are zero payload bytes.
247+
TEST(BitstreamIntegrationTest, EmptyStringRoundTripPreservesLengthPrefix)
248+
{
249+
std::stringstream stream;
250+
IO::OutputBitstream out(stream);
251+
252+
ASSERT_TRUE(out.write<std::string>(std::string()));
253+
// A 4-byte length prefix must have been written.
254+
EXPECT_EQ(out.size(), uint64_t(sizeof(unsigned int)));
255+
256+
IO::InputBitstream in(stream);
257+
std::string readback("previous");
258+
ASSERT_TRUE(in.read<std::string>(readback));
259+
EXPECT_TRUE(readback.empty());
260+
EXPECT_EQ(in.position(), uint64_t(sizeof(unsigned int)));
261+
}
262+
263+
} // namespace TestIO
264+
265+
} // namespace Test
266+
267+
} // namespace Ocean
268+
269+
#endif // OCEAN_USE_GTEST

0 commit comments

Comments
 (0)