1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 #ifdef HAVE_ZSTD
4 #include "zstd_decompressor.hpp"
5
6 #include <boost/asio/buffer.hpp>
7
8 #include <algorithm>
9 #include <array>
10 #include <cstddef>
11 #include <optional>
12 #include <span>
13
14 #include <gmock/gmock.h>
15 #include <gtest/gtest.h>
16
17 using ::testing::Each;
18 using ::testing::Eq;
19
20 namespace zstd
21 {
22 namespace
23 {
24
TEST(Zstd,EmptyFile)25 TEST(Zstd, EmptyFile)
26 {
27 std::array<unsigned char, 13> empty{0x28, 0xb5, 0x2f, 0xfd, 0x24,
28 0x00, 0x01, 0x00, 0x00, 0x99,
29 0xe9, 0xd8, 0x51};
30
31 ZstdDecompressor comp;
32 std::optional<boost::asio::const_buffer> out =
33 comp.decompress(boost::asio::buffer(empty));
34 ASSERT_TRUE(out);
35 if (!out)
36 {
37 return;
38 }
39 EXPECT_TRUE(out->size() == 0);
40 }
41
TEST(Zstd,ZerosFile)42 TEST(Zstd, ZerosFile)
43 {
44 // A 1MB file of all zeros created using
45 // dd if=/dev/zero of=zeros-file bs=1024 count=1024
46 // zstd -c zeros-file | xxd -i
47 std::array<unsigned char, 54> zeros = {
48 0x28, 0xb5, 0x2f, 0xfd, 0xa4, 0x00, 0x00, 0x10, 0x00, 0x54, 0x00,
49 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0xfb, 0xff, 0x39, 0xc0, 0x02,
50 0x02, 0x00, 0x10, 0x00, 0x02, 0x00, 0x10, 0x00, 0x02, 0x00, 0x10,
51 0x00, 0x02, 0x00, 0x10, 0x00, 0x02, 0x00, 0x10, 0x00, 0x02, 0x00,
52 0x10, 0x00, 0x03, 0x00, 0x10, 0x00, 0xf1, 0x3e, 0x16, 0xe1};
53
54 for (size_t chunkSize :
55 std::to_array<size_t>({1U, 2U, 4U, 8U, 16U, zeros.size()}))
56 {
57 ZstdDecompressor comp;
58 std::span<unsigned char> data = std::span(zeros);
59 size_t read = 0;
60 while (!data.empty())
61 {
62 std::span<unsigned char> chunk =
63 data.subspan(0, std::min(chunkSize, data.size()));
64 std::optional<boost::asio::const_buffer> out = comp.decompress(
65 boost::asio::buffer(chunk.data(), chunk.size()));
66 ASSERT_TRUE(out);
67 if (out)
68 {
69 EXPECT_THAT(
70 std::span(static_cast<const unsigned char*>(out->data()),
71 out->size()),
72 Each(Eq(0)));
73 read += out->size();
74 }
75 data = data.subspan(chunk.size());
76 }
77
78 EXPECT_EQ(read, 1024 * 1024);
79 }
80 }
81
TEST(Zstd,OnesFile)82 TEST(Zstd, OnesFile)
83 {
84 // A 1MB file of all ones created using
85 // dd if=/dev/zero bs=1024 count=1024 | tr "\000" "\377" > ones.txt
86 // zstd -c ones-file | xxd -i
87 std::array<unsigned char, 54> ones = {
88 0x28, 0xb5, 0x2f, 0xfd, 0xa4, 0x00, 0x00, 0x10, 0x00, 0x54, 0x00,
89 0x00, 0x10, 0xff, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x39, 0xc0, 0x02,
90 0x02, 0x00, 0x10, 0xff, 0x02, 0x00, 0x10, 0xff, 0x02, 0x00, 0x10,
91 0xff, 0x02, 0x00, 0x10, 0xff, 0x02, 0x00, 0x10, 0xff, 0x02, 0x00,
92 0x10, 0xff, 0x03, 0x00, 0x10, 0xff, 0xb4, 0xc8, 0xba, 0x13};
93
94 for (size_t chunkSize :
95 std::to_array<size_t>({1U, 2U, 4U, 8U, 16U, ones.size()}))
96 {
97 ZstdDecompressor comp;
98 std::span<unsigned char> data = std::span(ones);
99 size_t read = 0;
100 while (!data.empty())
101 {
102 std::span<unsigned char> chunk =
103 data.subspan(0, std::min(chunkSize, data.size()));
104 std::optional<boost::asio::const_buffer> out = comp.decompress(
105 boost::asio::buffer(chunk.data(), chunk.size()));
106 ASSERT_TRUE(out);
107 if (out)
108 {
109 EXPECT_THAT(
110 std::span(static_cast<const unsigned char*>(out->data()),
111 out->size()),
112 Each(Eq(0xFF)));
113 read += out->size();
114 }
115 data = data.subspan(chunk.size());
116 }
117
118 EXPECT_EQ(read, 1024 * 1024);
119 }
120 }
121
122 } // namespace
123 } // namespace zstd
124 #endif
125