Coverage Report

Created: 2023-12-13 14:58

test/zserio/BitStreamWriterTest.cpp
Line
Count
Source
1
#include <cstring>
2
#include <array>
3
4
#include "zserio/BitStreamWriter.h"
5
#include "zserio/CppRuntimeException.h"
6
7
#include "gtest/gtest.h"
8
9
namespace zserio
10
{
11
12
class BitStreamWriterTest : public ::testing::Test
13
{
14
public:
15
    BitStreamWriterTest() :
16
        m_externalBuffer(),
17
        m_externalBufferWriter(m_externalBuffer.data(), m_externalBuffer.size()),
18
        m_dummyBufferWriter(nullptr, 0)
19
24
    {
20
24
        m_externalBuffer.fill(0);
21
24
    }
22
23
protected:
24
    std::array<uint8_t, 512> m_externalBuffer;
25
    BitStreamWriter m_externalBufferWriter;
26
    BitStreamWriter m_dummyBufferWriter;
27
};
28
29
TEST_F(BitStreamWriterTest, rawConstructor)
30
1
{
31
1
    std::array<uint8_t, 2> data = { 0x00, 0x00 };
32
1
    BitStreamWriter writer(data.data(), data.size());
33
34
1
    ASSERT_EQ(data.data(), writer.getBuffer().data());
35
1
    ASSERT_EQ(data.size() * 8, writer.getBufferBitSize());
36
37
1
    writer.writeBits(0x1F, 5);
38
1
    writer.writeBits(0x07, 3);
39
1
    ASSERT_EQ(0xFF, writer.getBuffer()[0]);
40
1
    ASSERT_THROW(writer.writeBits(0xFFFF, 16), CppRuntimeException);
41
1
    writer.writeBits(0x07, 3);
42
1
    writer.writeBits(0x00, 5);
43
1
    ASSERT_EQ(0xE0, writer.getBuffer()[1]);
44
1
}
45
46
TEST_F(BitStreamWriterTest, rawConstructorWithBitSize)
47
1
{
48
1
    std::array<uint8_t, 2> data = { 0x00, 0x00 };
49
1
    BitStreamWriter writer(data.data(), 15, BitsTag());
50
51
1
    ASSERT_EQ(data.data(), writer.getBuffer().data());
52
1
    ASSERT_EQ(15, writer.getBufferBitSize());
53
54
1
    writer.writeBits(0x1F, 5);
55
1
    writer.writeBits(0x07, 3);
56
1
    ASSERT_EQ(0xFF, writer.getBuffer()[0]);
57
1
    ASSERT_THROW(writer.writeBits(0xFF, 8), CppRuntimeException);
58
1
    writer.writeBits(0x07, 3);
59
1
    writer.writeBits(0x00, 4);
60
1
    ASSERT_EQ(0xE0, writer.getBuffer()[1]);
61
1
}
62
63
TEST_F(BitStreamWriterTest, spanConstructor)
64
1
{
65
1
    std::array<uint8_t, 2> data = { 0x00, 0x00 };
66
1
    const Span<uint8_t> span(data);
67
1
    BitStreamWriter writer(span);
68
69
1
    ASSERT_EQ(span.data(), writer.getBuffer().data());
70
1
    ASSERT_EQ(span.size() * 8, writer.getBufferBitSize());
71
72
1
    writer.writeBits(0x1F, 5);
73
1
    writer.writeBits(0x07, 3);
74
1
    ASSERT_EQ(0xFF, writer.getBuffer()[0]);
75
1
    ASSERT_THROW(writer.writeBits(0xFFFF, 16), CppRuntimeException);
76
1
    writer.writeBits(0x07, 3);
77
1
    writer.writeBits(0x00, 5);
78
1
    ASSERT_EQ(0xE0, writer.getBuffer()[1]);
79
1
}
80
81
TEST_F(BitStreamWriterTest, spanConstructorWithBitSize)
82
1
{
83
1
    std::array<uint8_t, 2> data = { 0x00, 0x00 };
84
1
    const Span<uint8_t> span(data);
85
1
    BitStreamWriter writer(span, 15);
86
1
    ASSERT_THROW(BitStreamWriter wrongWriter(span, 17), CppRuntimeException);
87
88
1
    ASSERT_EQ(span.data(), writer.getBuffer().data());
89
1
    ASSERT_EQ(15, writer.getBufferBitSize());
90
91
1
    writer.writeBits(0x1F, 5);
92
1
    writer.writeBits(0x07, 3);
93
1
    ASSERT_EQ(0xFF, writer.getBuffer()[0]);
94
1
    ASSERT_THROW(writer.writeBits(0xFF, 8), CppRuntimeException);
95
1
    writer.writeBits(0x07, 3);
96
1
    writer.writeBits(0x00, 4);
97
1
    ASSERT_EQ(0xE0, writer.getBuffer()[1]);
98
1
}
99
100
TEST_F(BitStreamWriterTest, bitBufferConstructor)
101
1
{
102
1
    BitBuffer bitBuffer(11);
103
1
    BitStreamWriter writer(bitBuffer);
104
105
1
    ASSERT_EQ(bitBuffer.getBuffer(), writer.getBuffer().data());
106
1
    ASSERT_EQ(bitBuffer.getBitSize(), writer.getBufferBitSize());
107
108
1
    writer.writeBits(0x1F, 5);
109
1
    writer.writeBits(0x07, 3);
110
1
    ASSERT_EQ(0xFF, writer.getBuffer()[0]);
111
1
    ASSERT_THROW(writer.writeBits(0x0F, 4), CppRuntimeException);
112
1
    writer.writeBits(0x07, 3);
113
1
    ASSERT_EQ(0xE0, writer.getBuffer()[1]);
114
1
}
115
116
TEST_F(BitStreamWriterTest, writeUnalignedData)
117
1
{
118
    // number expected to be written at offset
119
1
    const uint8_t testValue = 123;
120
121
66
    for (uint8_t offset = 0; offset <= 64; 
++offset65
)
122
65
    {
123
65
        BitBuffer bitBuffer(8 + offset);
124
        // fill the buffer with 1s to check proper masking
125
65
        std::memset(bitBuffer.getBuffer(), 0xFF, bitBuffer.getByteSize());
126
127
65
        BitStreamWriter writer(bitBuffer);
128
129
65
        writer.writeBits64(0, offset);
130
65
        writer.writeBits(testValue, 8);
131
132
        // check eof
133
65
        ASSERT_THROW(writer.writeBits64(0, 1), CppRuntimeException);
134
135
        // check written value
136
65
        uint8_t writtenTestValue = static_cast<uint8_t>(bitBuffer.getData()[offset / 8U] << (offset % 8U));
137
65
        if (offset % 8 != 0)
138
56
        {
139
56
            writtenTestValue |=
140
56
                    static_cast<uint8_t>(bitBuffer.getData()[offset / 8U + 1U] >> (8U - (offset % 8U)));
141
56
        }
142
130
        ASSERT_EQ(testValue, writtenTestValue) << "Offset: " << offset;
143
65
    }
144
1
}
145
146
TEST_F(BitStreamWriterTest, writeBits)
147
1
{
148
    // check invalid bitlength acceptance
149
1
    const std::array<uint8_t, 3> numBitsArray = { 255, 0, 33 };
150
1
    for (uint8_t numBits : numBitsArray)
151
3
    {
152
3
        ASSERT_THROW(m_externalBufferWriter.writeBits(1, numBits), CppRuntimeException);
153
3
    }
154
155
    // check value out of range
156
32
    
for (int i = 1; 1
i < 32;
++i31
)
157
31
    {
158
31
        const uint32_t maxUnsigned = static_cast<uint32_t>((UINT64_C(1) << i) - 1);
159
31
        m_externalBufferWriter.writeBits(maxUnsigned, static_cast<uint8_t>(i));
160
161
31
        const uint32_t maxUnsignedViolation = maxUnsigned + 1;
162
31
        ASSERT_THROW(m_externalBufferWriter.writeBits(maxUnsignedViolation, static_cast<uint8_t>(i)),
163
31
                CppRuntimeException);
164
31
    }
165
1
}
166
167
TEST_F(BitStreamWriterTest, writeBits64)
168
1
{
169
    // check invalid bitlength acceptance
170
1
    const std::array<uint8_t, 3> numBitsArray = { 255, 0, 65 };
171
1
    for (uint8_t numBits : numBitsArray)
172
3
    {
173
3
        ASSERT_THROW(m_externalBufferWriter.writeBits64(1, numBits), CppRuntimeException);
174
3
    }
175
176
    // check value out of range
177
64
    
for (int i = 1; 1
i < 64;
++i63
)
178
63
    {
179
63
        const uint64_t maxUnsigned = (UINT64_C(1) << i) - 1;
180
63
        m_externalBufferWriter.writeBits64(maxUnsigned, static_cast<uint8_t>(i));
181
182
63
        const uint64_t maxUnsignedViolation = maxUnsigned + 1;
183
63
        ASSERT_THROW(m_externalBufferWriter.writeBits64(maxUnsignedViolation, static_cast<uint8_t>(i)),
184
63
                CppRuntimeException);
185
63
    }
186
1
}
187
188
TEST_F(BitStreamWriterTest, writeSignedBits)
189
1
{
190
    // check invalid bitlength acceptance
191
1
    const std::array<uint8_t, 3> numBitsArray = { 255, 0, 33 };
192
1
    for (uint8_t numBits : numBitsArray)
193
3
    {
194
3
        ASSERT_THROW(m_externalBufferWriter.writeSignedBits(1, numBits), CppRuntimeException);
195
3
    }
196
197
    // check value out of range
198
32
    
for (uint32_t i = 1; 1
i < 32;
++i31
)
199
31
    {
200
31
        const int32_t minSigned = -static_cast<int32_t>(1U << (i - 1U));
201
31
        const int32_t maxSigned =  static_cast<int32_t>((1U << (i - 1U)) - 1U);
202
31
        m_externalBufferWriter.writeSignedBits(minSigned, static_cast<uint8_t>(i));
203
31
        m_externalBufferWriter.writeSignedBits(maxSigned, static_cast<uint8_t>(i));
204
205
31
        const int32_t minSignedViolation = minSigned - 1;
206
31
        const int32_t maxSignedViolation = maxSigned + 1;
207
31
        ASSERT_THROW(m_externalBufferWriter.writeSignedBits(minSignedViolation, static_cast<uint8_t>(i)),
208
31
                CppRuntimeException);
209
31
        ASSERT_THROW(m_externalBufferWriter.writeSignedBits(maxSignedViolation, static_cast<uint8_t>(i)),
210
31
                CppRuntimeException);
211
31
    }
212
1
}
213
214
TEST_F(BitStreamWriterTest, writeSignedBits64)
215
1
{
216
    // check invalid bitlength acceptance
217
1
    const std::array<uint8_t, 3> numBitsArray = { 255, 0, 65 };
218
1
    for (uint8_t numBits : numBitsArray)
219
3
    {
220
3
        ASSERT_THROW(m_externalBufferWriter.writeSignedBits64(1, numBits), CppRuntimeException);
221
3
    }
222
223
    // check value out of range
224
64
    
for (int i = 1; 1
i < 64;
++i63
)
225
63
    {
226
63
        const int64_t minSigned = -(INT64_C(1) << (i - 1));
227
63
        const int64_t maxSigned =  (INT64_C(1) << (i - 1)) - 1;
228
63
        m_externalBufferWriter.writeSignedBits64(minSigned, static_cast<uint8_t>(i));
229
63
        m_externalBufferWriter.writeSignedBits64(maxSigned, static_cast<uint8_t>(i));
230
231
63
        const int64_t minSignedViolation = minSigned - 1;
232
63
        const int64_t maxSignedViolation = maxSigned + 1;
233
63
        ASSERT_THROW(m_externalBufferWriter.writeSignedBits64(minSignedViolation, static_cast<uint8_t>(i)),
234
63
                CppRuntimeException);
235
63
        ASSERT_THROW(m_externalBufferWriter.writeSignedBits64(maxSignedViolation, static_cast<uint8_t>(i)),
236
63
                CppRuntimeException);
237
63
    }
238
1
}
239
240
TEST_F(BitStreamWriterTest, writeVarInt64)
241
1
{
242
    // check value out of range
243
1
    const int64_t outOfRangeValue =
244
1
            static_cast<int64_t>(UINT64_C(1) << (6U + 7U + 7U + 7U + 7U + 7U + 7U + 8U));
245
1
    ASSERT_THROW(m_externalBufferWriter.writeVarInt64(outOfRangeValue), CppRuntimeException);
246
1
}
247
248
TEST_F(BitStreamWriterTest, writeVarInt32)
249
1
{
250
    // check value out of range
251
1
    const int32_t outOfRangeValue = static_cast<int32_t>(1U << (6U + 7U + 7U + 8U));
252
1
    ASSERT_THROW(m_externalBufferWriter.writeVarInt32(outOfRangeValue), CppRuntimeException);
253
1
}
254
255
TEST_F(BitStreamWriterTest, writeVarInt16)
256
1
{
257
    // check value out of range
258
1
    const int16_t outOfRangeValue = static_cast<int16_t>(1U << (6U + 8U));
259
1
    ASSERT_THROW(m_externalBufferWriter.writeVarInt16(outOfRangeValue), CppRuntimeException);
260
1
}
261
262
TEST_F(BitStreamWriterTest, writeVarUInt64)
263
1
{
264
    // check value out of range
265
1
    const uint64_t outOfRangeValue = UINT64_C(1) << (7U + 7U + 7U + 7U + 7U + 7U + 7U + 8U);
266
1
    ASSERT_THROW(m_externalBufferWriter.writeVarUInt64(outOfRangeValue), CppRuntimeException);
267
1
}
268
269
TEST_F(BitStreamWriterTest, writeVarUInt32)
270
1
{
271
    // check value out of range
272
1
    const uint32_t outOfRangeValue = UINT32_C(1) << (7U + 7U + 7U + 8U);
273
1
    ASSERT_THROW(m_externalBufferWriter.writeVarUInt32(outOfRangeValue), CppRuntimeException);
274
1
}
275
276
TEST_F(BitStreamWriterTest, writeVarUInt16)
277
1
{
278
    // check value out of range
279
1
    const uint16_t outOfRangeValue = static_cast<uint16_t>(1U << (7U + 8U));
280
1
    ASSERT_THROW(m_externalBufferWriter.writeVarUInt16(outOfRangeValue), CppRuntimeException);
281
1
}
282
283
TEST_F(BitStreamWriterTest, writeVarInt)
284
1
{
285
1
    ASSERT_NO_THROW(m_externalBufferWriter.writeVarInt(INT64_MIN));
286
1
    ASSERT_NO_THROW(m_externalBufferWriter.writeVarInt(INT64_MAX));
287
1
}
288
289
TEST_F(BitStreamWriterTest, writeVarUInt)
290
1
{
291
1
    ASSERT_NO_THROW(m_externalBufferWriter.writeVarUInt(0));
292
1
    ASSERT_NO_THROW(m_externalBufferWriter.writeVarUInt(UINT64_MAX));
293
1
}
294
295
TEST_F(BitStreamWriterTest, writeVarSize)
296
1
{
297
    // check value out of range
298
1
    const uint32_t outOfRangeValue = UINT32_C(1) << (2U + 7U + 7U + 7U + 8U);
299
1
    ASSERT_THROW(m_externalBufferWriter.writeVarSize(outOfRangeValue), CppRuntimeException);
300
1
}
301
302
TEST_F(BitStreamWriterTest, writeBitBuffer)
303
1
{
304
1
    static const size_t bitBufferBitSize = 24;
305
1
    BitBuffer bitBuffer(std::vector<uint8_t>{0xAB, 0xAB, 0xAB}, bitBufferBitSize);
306
307
1
    {
308
1
        ASSERT_NO_THROW(m_externalBufferWriter.writeBitBuffer(bitBuffer));
309
1
        Span<const uint8_t> buffer = m_externalBufferWriter.getBuffer();
310
1
        BitBuffer readBitBuffer{&buffer[1], bitBufferBitSize}; // first byte is bit buffer size
311
1
        ASSERT_EQ(bitBuffer, readBitBuffer);
312
1
    }
313
314
1
    ASSERT_NO_THROW(m_dummyBufferWriter.writeBitBuffer(bitBuffer));
315
1
    ASSERT_EQ(bitBufferBitSize + 8, m_dummyBufferWriter.getBitPosition()); // first byte is bit buffer size
316
1
}
317
318
TEST_F(BitStreamWriterTest, hasWriteBuffer)
319
1
{
320
1
    ASSERT_TRUE(m_externalBufferWriter.hasWriteBuffer());
321
1
    ASSERT_FALSE(m_dummyBufferWriter.hasWriteBuffer());
322
1
}
323
324
TEST_F(BitStreamWriterTest, getWriteBuffer)
325
1
{
326
1
    ASSERT_EQ(m_externalBuffer.data(), m_externalBufferWriter.getWriteBuffer());
327
328
1
    ASSERT_EQ(nullptr, m_dummyBufferWriter.getWriteBuffer());
329
1
}
330
331
TEST_F(BitStreamWriterTest, getBuffer)
332
1
{
333
1
    ASSERT_EQ(m_externalBuffer.data(), m_externalBufferWriter.getBuffer().data());
334
335
1
    ASSERT_EQ(nullptr, m_dummyBufferWriter.getBuffer().data());
336
1
}
337
338
TEST_F(BitStreamWriterTest, dummyBufferTest)
339
1
{
340
1
    m_dummyBufferWriter.writeBits(1, 1);
341
1
    m_dummyBufferWriter.alignTo(4);
342
1
    m_dummyBufferWriter.writeBits(1, 1);
343
1
    m_dummyBufferWriter.alignTo(4);
344
1
    m_dummyBufferWriter.writeBits(37, 11);
345
1
    m_dummyBufferWriter.alignTo(8);
346
1
    m_dummyBufferWriter.writeBits(1, 1);
347
1
    ASSERT_EQ(25, m_dummyBufferWriter.getBitPosition());
348
1
}
349
350
} // namespace zserio