GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: test/zserio/BitStreamWriterTest.cpp Lines: 178 178 100.0 %
Date: 2023-12-13 14:51:09 Branches: 494 1912 25.8 %

Line Branch Exec 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
24
class BitStreamWriterTest : public ::testing::Test
13
{
14
public:
15
24
    BitStreamWriterTest() :
16
        m_externalBuffer(),
17
        m_externalBufferWriter(m_externalBuffer.data(), m_externalBuffer.size()),
18

24
        m_dummyBufferWriter(nullptr, 0)
19
    {
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


802
TEST_F(BitStreamWriterTest, rawConstructor)
30
{
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









2
    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
}
45
46


802
TEST_F(BitStreamWriterTest, rawConstructorWithBitSize)
47
{
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









2
    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
}
62
63


802
TEST_F(BitStreamWriterTest, spanConstructor)
64
{
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









2
    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
}
80
81


802
TEST_F(BitStreamWriterTest, spanConstructorWithBitSize)
82
{
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









2
    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









2
    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
}
99
100


802
TEST_F(BitStreamWriterTest, bitBufferConstructor)
101
{
102
2
    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









2
    ASSERT_THROW(writer.writeBits(0x0F, 4), CppRuntimeException);
112
1
    writer.writeBits(0x07, 3);
113




1
    ASSERT_EQ(0xE0, writer.getBuffer()[1]);
114
}
115
116


802
TEST_F(BitStreamWriterTest, writeUnalignedData)
117
{
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; ++offset)
122
    {
123

130
        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









130
        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
        {
139
            writtenTestValue |=
140
56
                    static_cast<uint8_t>(bitBuffer.getData()[offset / 8U + 1U] >> (8U - (offset % 8U)));
141
        }
142




65
        ASSERT_EQ(testValue, writtenTestValue) << "Offset: " << offset;
143
    }
144
}
145
146


802
TEST_F(BitStreamWriterTest, writeBits)
147
{
148
    // check invalid bitlength acceptance
149
1
    const std::array<uint8_t, 3> numBitsArray = { 255, 0, 33 };
150
4
    for (uint8_t numBits : numBitsArray)
151
    {
152










6
        ASSERT_THROW(m_externalBufferWriter.writeBits(1, numBits), CppRuntimeException);
153
    }
154
155
    // check value out of range
156

32
    for (int i = 1; i < 32; ++i)
157
    {
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









62
        ASSERT_THROW(m_externalBufferWriter.writeBits(maxUnsignedViolation, static_cast<uint8_t>(i)),
163
                CppRuntimeException);
164
    }
165
}
166
167


802
TEST_F(BitStreamWriterTest, writeBits64)
168
{
169
    // check invalid bitlength acceptance
170
1
    const std::array<uint8_t, 3> numBitsArray = { 255, 0, 65 };
171
4
    for (uint8_t numBits : numBitsArray)
172
    {
173










6
        ASSERT_THROW(m_externalBufferWriter.writeBits64(1, numBits), CppRuntimeException);
174
    }
175
176
    // check value out of range
177

64
    for (int i = 1; i < 64; ++i)
178
    {
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









126
        ASSERT_THROW(m_externalBufferWriter.writeBits64(maxUnsignedViolation, static_cast<uint8_t>(i)),
184
                CppRuntimeException);
185
    }
186
}
187
188


802
TEST_F(BitStreamWriterTest, writeSignedBits)
189
{
190
    // check invalid bitlength acceptance
191
1
    const std::array<uint8_t, 3> numBitsArray = { 255, 0, 33 };
192
4
    for (uint8_t numBits : numBitsArray)
193
    {
194










6
        ASSERT_THROW(m_externalBufferWriter.writeSignedBits(1, numBits), CppRuntimeException);
195
    }
196
197
    // check value out of range
198

32
    for (uint32_t i = 1; i < 32; ++i)
199
    {
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










62
        ASSERT_THROW(m_externalBufferWriter.writeSignedBits(minSignedViolation, static_cast<uint8_t>(i)),
208
                CppRuntimeException);
209









62
        ASSERT_THROW(m_externalBufferWriter.writeSignedBits(maxSignedViolation, static_cast<uint8_t>(i)),
210
                CppRuntimeException);
211
    }
212
}
213
214


802
TEST_F(BitStreamWriterTest, writeSignedBits64)
215
{
216
    // check invalid bitlength acceptance
217
1
    const std::array<uint8_t, 3> numBitsArray = { 255, 0, 65 };
218
4
    for (uint8_t numBits : numBitsArray)
219
    {
220










6
        ASSERT_THROW(m_externalBufferWriter.writeSignedBits64(1, numBits), CppRuntimeException);
221
    }
222
223
    // check value out of range
224

64
    for (int i = 1; i < 64; ++i)
225
    {
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










126
        ASSERT_THROW(m_externalBufferWriter.writeSignedBits64(minSignedViolation, static_cast<uint8_t>(i)),
234
                CppRuntimeException);
235









126
        ASSERT_THROW(m_externalBufferWriter.writeSignedBits64(maxSignedViolation, static_cast<uint8_t>(i)),
236
                CppRuntimeException);
237
    }
238
}
239
240


802
TEST_F(BitStreamWriterTest, writeVarInt64)
241
{
242
    // check value out of range
243
    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
}
247
248


802
TEST_F(BitStreamWriterTest, writeVarInt32)
249
{
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
}
254
255


802
TEST_F(BitStreamWriterTest, writeVarInt16)
256
{
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
}
261
262


802
TEST_F(BitStreamWriterTest, writeVarUInt64)
263
{
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
}
268
269


802
TEST_F(BitStreamWriterTest, writeVarUInt32)
270
{
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
}
275
276


802
TEST_F(BitStreamWriterTest, writeVarUInt16)
277
{
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
}
282
283


802
TEST_F(BitStreamWriterTest, writeVarInt)
284
{
285









1
    ASSERT_NO_THROW(m_externalBufferWriter.writeVarInt(INT64_MIN));
286









1
    ASSERT_NO_THROW(m_externalBufferWriter.writeVarInt(INT64_MAX));
287
}
288
289


802
TEST_F(BitStreamWriterTest, writeVarUInt)
290
{
291









1
    ASSERT_NO_THROW(m_externalBufferWriter.writeVarUInt(0));
292









1
    ASSERT_NO_THROW(m_externalBufferWriter.writeVarUInt(UINT64_MAX));
293
}
294
295


802
TEST_F(BitStreamWriterTest, writeVarSize)
296
{
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
}
301
302


802
TEST_F(BitStreamWriterTest, writeBitBuffer)
303
{
304
    static const size_t bitBufferBitSize = 24;
305

2
    BitBuffer bitBuffer(std::vector<uint8_t>{0xAB, 0xAB, 0xAB}, bitBufferBitSize);
306
307
    {
308








1
        ASSERT_NO_THROW(m_externalBufferWriter.writeBitBuffer(bitBuffer));
309
1
        Span<const uint8_t> buffer = m_externalBufferWriter.getBuffer();
310

2
        BitBuffer readBitBuffer{&buffer[1], bitBufferBitSize}; // first byte is bit buffer size
311



1
        ASSERT_EQ(bitBuffer, readBitBuffer);
312
    }
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
}
317
318


802
TEST_F(BitStreamWriterTest, hasWriteBuffer)
319
{
320



1
    ASSERT_TRUE(m_externalBufferWriter.hasWriteBuffer());
321



1
    ASSERT_FALSE(m_dummyBufferWriter.hasWriteBuffer());
322
}
323
324


802
TEST_F(BitStreamWriterTest, getWriteBuffer)
325
{
326



1
    ASSERT_EQ(m_externalBuffer.data(), m_externalBufferWriter.getWriteBuffer());
327
328



1
    ASSERT_EQ(nullptr, m_dummyBufferWriter.getWriteBuffer());
329
}
330
331


802
TEST_F(BitStreamWriterTest, getBuffer)
332
{
333



1
    ASSERT_EQ(m_externalBuffer.data(), m_externalBufferWriter.getBuffer().data());
334
335



1
    ASSERT_EQ(nullptr, m_dummyBufferWriter.getBuffer().data());
336
}
337
338


802
TEST_F(BitStreamWriterTest, dummyBufferTest)
339
{
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
}
349
350

2394
} // namespace zserio