Coverage Report

Created: 2024-07-18 11:41

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