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