|
21 | 21 | #include <iostream>
|
22 | 22 | #include <memory>
|
23 | 23 | #include <string>
|
| 24 | +#include <string_view> |
24 | 25 | #include <vector>
|
25 | 26 |
|
26 | 27 | #include "gtest/gtest.h"
|
@@ -1047,5 +1048,135 @@ TEST(ZLibWrapperStandalone, ReadPastEndOfWindow) {
|
1047 | 1048 | LOG(INFO) << "passed read-past-end-of-window test";
|
1048 | 1049 | }
|
1049 | 1050 |
|
| 1051 | +TEST(ZLibWrapperStandalone, BytewiseRead) { |
| 1052 | + std::string text = |
| 1053 | + "v nedrah tundry vydra v getrah tyrit v vedrah yadra kedra"; |
| 1054 | + size_t text_len = text.size(); |
| 1055 | + size_t archive_len = ZLib::MinCompressbufSize(text_len); |
| 1056 | + std::string archive(archive_len, '\0'); |
| 1057 | + size_t decompressed_len = text_len + 1; |
| 1058 | + std::string decompressed(decompressed_len, '\0'); |
| 1059 | + size_t decompressed_offset = 0; |
| 1060 | + |
| 1061 | + ZLib compressor; |
| 1062 | + compressor.SetGzipHeaderMode(); |
| 1063 | + int rc = compressor.Compress((Bytef*)archive.data(), &archive_len, |
| 1064 | + (Bytef*)text.data(), text_len); |
| 1065 | + ASSERT_EQ(rc, Z_OK); |
| 1066 | + |
| 1067 | + ZLib zlib; |
| 1068 | + zlib.SetGzipHeaderMode(); |
| 1069 | + for (size_t i = 0; i < archive_len; ++i) { |
| 1070 | + size_t source_len = 1; |
| 1071 | + size_t dest_len = decompressed_len - decompressed_offset; |
| 1072 | + rc = zlib.UncompressAtMost( |
| 1073 | + (Bytef*)decompressed.data() + decompressed_offset, &dest_len, |
| 1074 | + (Bytef*)archive.data() + i, &source_len); |
| 1075 | + ASSERT_EQ(rc, Z_OK); |
| 1076 | + ASSERT_EQ(source_len, 0); |
| 1077 | + decompressed_offset += dest_len; |
| 1078 | + } |
| 1079 | + |
| 1080 | + ASSERT_TRUE(zlib.IsGzipFooterValid()); |
| 1081 | + ASSERT_EQ(decompressed_offset, text_len); |
| 1082 | + |
| 1083 | + std::string truncated_output(decompressed.data(), text_len); |
| 1084 | + ASSERT_EQ(truncated_output, text); |
| 1085 | + |
| 1086 | + // if we haven't segfaulted by now, we pass |
| 1087 | + LOG(INFO) << "passed bytewise-read test"; |
| 1088 | +} |
| 1089 | + |
| 1090 | +TEST(ZLibWrapperStandaloneTest, TruncatedData) { |
| 1091 | + const int kBufferLen = 64; |
| 1092 | + std::string uncompressed = "Hello, World!"; |
| 1093 | + std::string compressed( |
| 1094 | + "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xf3\x48\xcd\xc9\xc9" |
| 1095 | + "\xd7\x51\x08\xcf\x2f\xca\x49\x51\x04\x00\xd0\xc3\x4a\xec\x0d" |
| 1096 | + "\x00\x00\x00", |
| 1097 | + 33); |
| 1098 | + |
| 1099 | + // Verify that "compressed" contains valid gzip data. |
| 1100 | + { |
| 1101 | + ZLib zlib; |
| 1102 | + zlib.SetGzipHeaderMode(); |
| 1103 | + char uncompbuf[kBufferLen]; |
| 1104 | + bzero(uncompbuf, kBufferLen); |
| 1105 | + uLongf uncomplen = kBufferLen; |
| 1106 | + int err = zlib.Uncompress( |
| 1107 | + reinterpret_cast<Bytef*>(uncompbuf), &uncomplen, |
| 1108 | + reinterpret_cast<const Bytef*>(compressed.c_str()), compressed.size()); |
| 1109 | + ASSERT_EQ(err, Z_OK); |
| 1110 | + ASSERT_EQ(uncompressed, std::string_view(uncompbuf, uncomplen)); |
| 1111 | + } |
| 1112 | + |
| 1113 | + // Test truncated data with ZLib::Uncompress(). |
| 1114 | + for (int len = compressed.size() - 1; len > 0; len--) { |
| 1115 | + SCOPED_TRACE(absl::StrCat("Decompressing first ", len, " out of ", |
| 1116 | + compressed.size(), " bytes")); |
| 1117 | + ZLib zlib; |
| 1118 | + zlib.SetGzipHeaderMode(); |
| 1119 | + char uncompbuf[kBufferLen]; |
| 1120 | + bzero(uncompbuf, kBufferLen); |
| 1121 | + uLongf uncomplen = kBufferLen; |
| 1122 | + int err = zlib.Uncompress( |
| 1123 | + reinterpret_cast<Bytef*>(uncompbuf), &uncomplen, |
| 1124 | + reinterpret_cast<const Bytef*>(compressed.c_str()), len); |
| 1125 | + ASSERT_NE(err, Z_OK); |
| 1126 | + } |
| 1127 | + |
| 1128 | + // Test truncated data with ZLib::UncompressAtMost() and |
| 1129 | + // ZLib::UncompressDone(). |
| 1130 | + for (int len = compressed.size() - 1; len > 0; len--) { |
| 1131 | + SCOPED_TRACE(absl::StrCat("Decompressing first ", len, " out of ", |
| 1132 | + compressed.size(), " bytes")); |
| 1133 | + ZLib zlib; |
| 1134 | + zlib.SetGzipHeaderMode(); |
| 1135 | + char uncompbuf[kBufferLen]; |
| 1136 | + bzero(uncompbuf, kBufferLen); |
| 1137 | + uLongf uncomplen = kBufferLen; |
| 1138 | + uLongf complen = len; |
| 1139 | + int err = zlib.UncompressAtMost( |
| 1140 | + reinterpret_cast<Bytef*>(uncompbuf), &uncomplen, |
| 1141 | + reinterpret_cast<const Bytef*>(compressed.c_str()), &complen); |
| 1142 | + ASSERT_EQ(err, Z_OK); |
| 1143 | + ASSERT_EQ(complen, 0); |
| 1144 | + if (uncomplen > 0) { |
| 1145 | + EXPECT_THAT(uncompressed, |
| 1146 | + testing::StartsWith(absl::string_view(uncompbuf, uncomplen))); |
| 1147 | + } |
| 1148 | + ASSERT_FALSE(zlib.UncompressChunkDone()); |
| 1149 | + } |
| 1150 | +} |
| 1151 | + |
| 1152 | +TEST(ZLibWrapperStandalone, GzipUncompressedLength) { |
| 1153 | + ZLib zlib; |
| 1154 | + |
| 1155 | + // "Hello, World!", compressed. |
| 1156 | + std::string hello_world( |
| 1157 | + "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xf3\x48\xcd\xc9\xc9" |
| 1158 | + "\xd7\x51\x08\xcf\x2f\xca\x49\x51\x04\x00\xd0\xc3\x4a\xec\x0d" |
| 1159 | + "\x00\x00\x00", |
| 1160 | + 33); |
| 1161 | + EXPECT_EQ(13, zlib.GzipUncompressedLength( |
| 1162 | + reinterpret_cast<const Bytef*>(hello_world.c_str()), |
| 1163 | + hello_world.size())); |
| 1164 | + |
| 1165 | + // Empty string, "", compressed. |
| 1166 | + std::string empty( |
| 1167 | + "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\x03\x00\x00\x00\x00" |
| 1168 | + "\x00\x00\x00\x00\x00", |
| 1169 | + 20); |
| 1170 | + EXPECT_EQ(0, |
| 1171 | + zlib.GzipUncompressedLength( |
| 1172 | + reinterpret_cast<const Bytef*>(empty.c_str()), empty.size())); |
| 1173 | + |
| 1174 | + std::string bad_data("\x01\x01\x01\x01", 4); |
| 1175 | + for (int len = 0; len <= bad_data.size(); len++) { |
| 1176 | + EXPECT_EQ(0, zlib.GzipUncompressedLength( |
| 1177 | + reinterpret_cast<const Bytef*>(bad_data.c_str()), len)); |
| 1178 | + } |
| 1179 | +} |
| 1180 | + |
1050 | 1181 | } // namespace
|
1051 | 1182 | } // namespace firebase
|
0 commit comments