xref: /openbmc/bmcweb/test/http/zstd_compressor_test.cpp (revision f485bd44a22c27a2346a69d740764ea98b333bd1)
1*f485bd44SEd Tanous // SPDX-License-Identifier: Apache-2.0
2*f485bd44SEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3*f485bd44SEd Tanous #include <boost/asio/buffer.hpp>
4*f485bd44SEd Tanous 
5*f485bd44SEd Tanous #include <algorithm>
6*f485bd44SEd Tanous #include <climits>
7*f485bd44SEd Tanous #include <cstdint>
8*f485bd44SEd Tanous #include <functional>
9*f485bd44SEd Tanous #include <vector>
10*f485bd44SEd Tanous #ifdef HAVE_ZSTD
11*f485bd44SEd Tanous #include "zstd_compressor.hpp"
12*f485bd44SEd Tanous #include "zstd_decompressor.hpp"
13*f485bd44SEd Tanous #include "zstd_test_arrays.hpp"
14*f485bd44SEd Tanous 
15*f485bd44SEd Tanous #include <cstddef>
16*f485bd44SEd Tanous #include <optional>
17*f485bd44SEd Tanous #include <random>
18*f485bd44SEd Tanous #include <span>
19*f485bd44SEd Tanous 
20*f485bd44SEd Tanous #include <gmock/gmock.h>
21*f485bd44SEd Tanous #include <gtest/gtest.h>
22*f485bd44SEd Tanous 
23*f485bd44SEd Tanous using ::testing::ElementsAreArray;
24*f485bd44SEd Tanous 
25*f485bd44SEd Tanous namespace bmcweb
26*f485bd44SEd Tanous {
27*f485bd44SEd Tanous namespace
28*f485bd44SEd Tanous {
29*f485bd44SEd Tanous 
TEST(ZstdCompressor,EmptyFile)30*f485bd44SEd Tanous TEST(ZstdCompressor, EmptyFile)
31*f485bd44SEd Tanous {
32*f485bd44SEd Tanous     ZstdCompressor comp;
33*f485bd44SEd Tanous     ASSERT_TRUE(comp.init(0U));
34*f485bd44SEd Tanous     std::vector<uint8_t> out;
35*f485bd44SEd Tanous     bool more = false;
36*f485bd44SEd Tanous     std::vector<uint8_t> empty;
37*f485bd44SEd Tanous     std::optional<std::span<const uint8_t>> segmentOut =
38*f485bd44SEd Tanous         comp.compress(empty, more);
39*f485bd44SEd Tanous     ASSERT_TRUE(segmentOut);
40*f485bd44SEd Tanous     if (!segmentOut)
41*f485bd44SEd Tanous     {
42*f485bd44SEd Tanous         return;
43*f485bd44SEd Tanous     }
44*f485bd44SEd Tanous 
45*f485bd44SEd Tanous     EXPECT_THAT(*segmentOut, ElementsAreArray(zstd::empty));
46*f485bd44SEd Tanous }
47*f485bd44SEd Tanous 
TEST(ZstdCompressor,AllZeros)48*f485bd44SEd Tanous TEST(ZstdCompressor, AllZeros)
49*f485bd44SEd Tanous {
50*f485bd44SEd Tanous     for (size_t chunkSize : {1U, 2U, 4U, 8U, 1024U, 1048576U})
51*f485bd44SEd Tanous     {
52*f485bd44SEd Tanous         ZstdCompressor comp;
53*f485bd44SEd Tanous         constexpr size_t fileSize = 1048576U;
54*f485bd44SEd Tanous         ASSERT_TRUE(comp.init(fileSize));
55*f485bd44SEd Tanous         std::vector<uint8_t> out;
56*f485bd44SEd Tanous 
57*f485bd44SEd Tanous         std::vector<uint8_t> zeros(chunkSize, 0x00);
58*f485bd44SEd Tanous         for (size_t i = 0; i < fileSize; i += chunkSize)
59*f485bd44SEd Tanous         {
60*f485bd44SEd Tanous             bool more = i != fileSize - chunkSize;
61*f485bd44SEd Tanous             std::optional<std::span<const uint8_t>> segmentOut =
62*f485bd44SEd Tanous                 comp.compress(zeros, more);
63*f485bd44SEd Tanous             ASSERT_TRUE(segmentOut);
64*f485bd44SEd Tanous             if (!segmentOut)
65*f485bd44SEd Tanous             {
66*f485bd44SEd Tanous                 return;
67*f485bd44SEd Tanous             }
68*f485bd44SEd Tanous             out.insert(out.end(), segmentOut->begin(), segmentOut->end());
69*f485bd44SEd Tanous         }
70*f485bd44SEd Tanous         EXPECT_THAT(out, ElementsAreArray(zstd::zeros));
71*f485bd44SEd Tanous     }
72*f485bd44SEd Tanous }
73*f485bd44SEd Tanous 
TEST(ZstdCompressor,AllOnes)74*f485bd44SEd Tanous TEST(ZstdCompressor, AllOnes)
75*f485bd44SEd Tanous {
76*f485bd44SEd Tanous     ZstdCompressor comp;
77*f485bd44SEd Tanous     ASSERT_TRUE(comp.init(1048576U));
78*f485bd44SEd Tanous     std::vector<uint8_t> out;
79*f485bd44SEd Tanous     std::vector<uint8_t> zeros(1024U, 0xFF);
80*f485bd44SEd Tanous     for (size_t i = 0; i < 1024U; i++)
81*f485bd44SEd Tanous     {
82*f485bd44SEd Tanous         bool more = i < 1023U;
83*f485bd44SEd Tanous         std::optional<std::span<const uint8_t>> segmentOut =
84*f485bd44SEd Tanous             comp.compress(zeros, more);
85*f485bd44SEd Tanous         ASSERT_TRUE(segmentOut);
86*f485bd44SEd Tanous         if (!segmentOut)
87*f485bd44SEd Tanous         {
88*f485bd44SEd Tanous             return;
89*f485bd44SEd Tanous         }
90*f485bd44SEd Tanous         out.insert(out.end(), segmentOut->begin(), segmentOut->end());
91*f485bd44SEd Tanous     }
92*f485bd44SEd Tanous 
93*f485bd44SEd Tanous     EXPECT_THAT(out, ElementsAreArray(zstd::ones));
94*f485bd44SEd Tanous }
95*f485bd44SEd Tanous 
TEST(Zstd,RoundTrip)96*f485bd44SEd Tanous TEST(Zstd, RoundTrip)
97*f485bd44SEd Tanous {
98*f485bd44SEd Tanous     using random_bytes_engine =
99*f485bd44SEd Tanous         std::independent_bits_engine<std::default_random_engine, CHAR_BIT,
100*f485bd44SEd Tanous                                      unsigned char>;
101*f485bd44SEd Tanous 
102*f485bd44SEd Tanous     // This is a unit test, we WANT reproducible tests
103*f485bd44SEd Tanous     // NOLINTNEXTLINE(cert-msc51-cpp, cert-msc32-c)
104*f485bd44SEd Tanous     random_bytes_engine rbe;
105*f485bd44SEd Tanous     std::vector<unsigned char> data(1048576U);
106*f485bd44SEd Tanous     std::ranges::generate(data, std::ref(rbe));
107*f485bd44SEd Tanous 
108*f485bd44SEd Tanous     for (size_t chunkSize : {1U, 2U, 4U, 8U, 1024U, 1048576U})
109*f485bd44SEd Tanous     {
110*f485bd44SEd Tanous         ZstdCompressor comp;
111*f485bd44SEd Tanous         std::vector<uint8_t> compressed;
112*f485bd44SEd Tanous         ASSERT_TRUE(comp.init(data.size()));
113*f485bd44SEd Tanous         for (size_t i = 0; i < data.size(); i += chunkSize)
114*f485bd44SEd Tanous         {
115*f485bd44SEd Tanous             bool more = i != data.size() - chunkSize;
116*f485bd44SEd Tanous             std::optional<std::span<const uint8_t>> segmentOut =
117*f485bd44SEd Tanous                 comp.compress(std::span(data).subspan(i, chunkSize), more);
118*f485bd44SEd Tanous             ASSERT_TRUE(segmentOut);
119*f485bd44SEd Tanous             if (!segmentOut)
120*f485bd44SEd Tanous             {
121*f485bd44SEd Tanous                 return;
122*f485bd44SEd Tanous             }
123*f485bd44SEd Tanous             compressed.insert(compressed.end(), segmentOut->begin(),
124*f485bd44SEd Tanous                               segmentOut->end());
125*f485bd44SEd Tanous         }
126*f485bd44SEd Tanous         ZstdDecompressor decomp;
127*f485bd44SEd Tanous 
128*f485bd44SEd Tanous         std::optional<boost::asio::const_buffer> segmentOut =
129*f485bd44SEd Tanous             decomp.decompress(boost::asio::buffer(compressed));
130*f485bd44SEd Tanous         ASSERT_TRUE(segmentOut);
131*f485bd44SEd Tanous         if (!segmentOut)
132*f485bd44SEd Tanous         {
133*f485bd44SEd Tanous             continue;
134*f485bd44SEd Tanous         }
135*f485bd44SEd Tanous         std::span<const uint8_t> decompressedSpan = std::span<const uint8_t>(
136*f485bd44SEd Tanous             static_cast<const uint8_t*>(segmentOut->data()),
137*f485bd44SEd Tanous             segmentOut->size());
138*f485bd44SEd Tanous 
139*f485bd44SEd Tanous         EXPECT_THAT(decompressedSpan, ElementsAreArray(data));
140*f485bd44SEd Tanous     }
141*f485bd44SEd Tanous }
142*f485bd44SEd Tanous 
143*f485bd44SEd Tanous } // namespace
144*f485bd44SEd Tanous } // namespace bmcweb
145*f485bd44SEd Tanous #endif
146