/third_party/puffin/src/puff_io_unittest.cc

https://github.com/chromium/chromium · C++ · 399 lines · 337 code · 38 blank · 24 comment · 12 complexity · 0318fa636b66a2b06d8ed00caf0699ff MD5 · raw file

  1. // Copyright 2017 The Chromium OS Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "gtest/gtest.h"
  5. #include "puffin/src/puff_reader.h"
  6. #include "puffin/src/puff_writer.h"
  7. #include "puffin/src/unittest_common.h"
  8. namespace puffin {
  9. namespace {
  10. void TestLiteralLength(size_t length) {
  11. Buffer buf(length + 10);
  12. PuffData pd;
  13. BufferPuffWriter pw(buf.data(), buf.size());
  14. // We need to insert a metadata otherwise it will fail.
  15. pd.type = PuffData::Type::kBlockMetadata;
  16. pd.length = 1;
  17. ASSERT_TRUE(pw.Insert(pd));
  18. BufferPuffReader pr(buf.data(), buf.size());
  19. ASSERT_TRUE(pr.GetNext(&pd));
  20. ASSERT_EQ(pd.type, PuffData::Type::kBlockMetadata);
  21. ASSERT_EQ(pd.length, 1);
  22. // We insert |length| bytes.
  23. pd.type = PuffData::Type::kLiterals;
  24. pd.length = length;
  25. pd.read_fn = [](uint8_t* buffer, size_t count) {
  26. std::fill(buffer, buffer + count, 10);
  27. return true;
  28. };
  29. ASSERT_TRUE(pw.Insert(pd));
  30. ASSERT_TRUE(pw.Flush());
  31. pd.type = PuffData::Type::kLenDist;
  32. pd.distance = 1;
  33. pd.length = 3;
  34. ASSERT_TRUE(pw.Insert(pd));
  35. ASSERT_TRUE(pr.GetNext(&pd));
  36. if (length == 0) {
  37. // If length is zero, then nothing should've been inserted.
  38. ASSERT_EQ(pd.type, PuffData::Type::kLenDist);
  39. } else {
  40. // We have to see |length| bytes.
  41. ASSERT_EQ(pd.type, PuffData::Type::kLiterals);
  42. ASSERT_EQ(pd.length, length);
  43. for (size_t i = 0; i < pd.length; i++) {
  44. uint8_t byte;
  45. pd.read_fn(&byte, 1);
  46. EXPECT_EQ(byte, 10);
  47. }
  48. }
  49. }
  50. } // namespace
  51. // Testing read/write from/into a puff buffer using |PuffReader|/|PuffWriter|.
  52. TEST(PuffIOTest, InputOutputTest) {
  53. Buffer buf(100);
  54. BufferPuffReader pr(buf.data(), buf.size());
  55. BufferPuffWriter pw(buf.data(), buf.size());
  56. BufferPuffWriter epw(nullptr, 0);
  57. uint8_t block = 123;
  58. {
  59. PuffData pd;
  60. pd.type = PuffData::Type::kBlockMetadata;
  61. pd.block_metadata[0] = 0xCC; // header
  62. memcpy(&pd.block_metadata[1], &block, sizeof(block));
  63. pd.length = sizeof(block) + 1;
  64. ASSERT_TRUE(pw.Insert(pd));
  65. ASSERT_TRUE(epw.Insert(pd));
  66. ASSERT_TRUE(pw.Flush());
  67. ASSERT_TRUE(epw.Flush());
  68. }
  69. {
  70. PuffData pd;
  71. ASSERT_TRUE(pr.GetNext(&pd));
  72. ASSERT_EQ(pd.type, PuffData::Type::kBlockMetadata);
  73. ASSERT_EQ(pd.length, sizeof(block) + 1);
  74. ASSERT_EQ(pd.block_metadata[0], 0xCC);
  75. ASSERT_EQ(pd.block_metadata[1], block);
  76. }
  77. {
  78. PuffData pd;
  79. pd.type = PuffData::Type::kLenDist;
  80. pd.distance = 321;
  81. pd.length = 3;
  82. ASSERT_TRUE(pw.Insert(pd));
  83. ASSERT_TRUE(epw.Insert(pd));
  84. pd.length = 127;
  85. ASSERT_TRUE(pw.Insert(pd));
  86. ASSERT_TRUE(epw.Insert(pd));
  87. pd.length = 258;
  88. ASSERT_TRUE(pw.Insert(pd));
  89. ASSERT_TRUE(epw.Insert(pd));
  90. ASSERT_TRUE(pw.Flush());
  91. ASSERT_TRUE(epw.Flush());
  92. pd.length = 259;
  93. ASSERT_FALSE(pw.Insert(pd));
  94. ASSERT_FALSE(epw.Insert(pd));
  95. }
  96. {
  97. PuffData pd;
  98. ASSERT_TRUE(pr.GetNext(&pd));
  99. ASSERT_EQ(pd.type, PuffData::Type::kLenDist);
  100. ASSERT_EQ(pd.distance, 321);
  101. ASSERT_EQ(pd.length, 3);
  102. ASSERT_TRUE(pr.GetNext(&pd));
  103. ASSERT_EQ(pd.type, PuffData::Type::kLenDist);
  104. ASSERT_EQ(pd.length, 127);
  105. ASSERT_TRUE(pr.GetNext(&pd));
  106. ASSERT_EQ(pd.type, PuffData::Type::kLenDist);
  107. ASSERT_EQ(pd.length, 258);
  108. }
  109. {
  110. PuffData pd;
  111. pd.type = PuffData::Type::kEndOfBlock;
  112. ASSERT_TRUE(pw.Insert(pd));
  113. ASSERT_TRUE(epw.Insert(pd));
  114. ASSERT_TRUE(pw.Flush());
  115. ASSERT_TRUE(epw.Flush());
  116. }
  117. {
  118. PuffData pd;
  119. ASSERT_TRUE(pr.GetNext(&pd));
  120. ASSERT_EQ(pd.type, PuffData::Type::kEndOfBlock);
  121. }
  122. {
  123. PuffData pd;
  124. pd.type = PuffData::Type::kBlockMetadata;
  125. block = 123;
  126. pd.block_metadata[0] = 0xCC; // header
  127. memcpy(&pd.block_metadata[1], &block, sizeof(block));
  128. pd.length = sizeof(block) + 1;
  129. ASSERT_TRUE(pw.Insert(pd));
  130. ASSERT_TRUE(epw.Insert(pd));
  131. ASSERT_TRUE(pw.Flush());
  132. ASSERT_TRUE(epw.Flush());
  133. }
  134. {
  135. PuffData pd;
  136. ASSERT_TRUE(pr.GetNext(&pd));
  137. ASSERT_EQ(pd.type, PuffData::Type::kBlockMetadata);
  138. ASSERT_EQ(pd.length, sizeof(block) + 1);
  139. ASSERT_EQ(pd.block_metadata[0], 0xCC);
  140. ASSERT_EQ(pd.block_metadata[1], block);
  141. }
  142. uint8_t tmp[] = {1, 2, 100};
  143. {
  144. PuffData pd;
  145. size_t index = 0;
  146. pd.type = PuffData::Type::kLiterals;
  147. pd.length = 3;
  148. pd.read_fn = [&tmp, &index](uint8_t* buffer, size_t count) {
  149. if (count > 3 - index)
  150. return false;
  151. if (buffer != nullptr) {
  152. memcpy(buffer, &tmp[index], count);
  153. }
  154. index += count;
  155. return true;
  156. };
  157. ASSERT_TRUE(pw.Insert(pd));
  158. ASSERT_TRUE(pw.Flush());
  159. // We have to refresh the read_fn function for the second insert.
  160. index = 0;
  161. ASSERT_TRUE(epw.Insert(pd));
  162. ASSERT_TRUE(epw.Flush());
  163. }
  164. {
  165. PuffData pd;
  166. pd.type = PuffData::Type::kLiteral;
  167. pd.byte = 10;
  168. ASSERT_TRUE(pw.Insert(pd));
  169. ASSERT_TRUE(epw.Insert(pd));
  170. ASSERT_TRUE(pw.Flush());
  171. ASSERT_TRUE(epw.Flush());
  172. }
  173. uint8_t tmp3[3];
  174. {
  175. PuffData pd;
  176. ASSERT_TRUE(pr.GetNext(&pd));
  177. ASSERT_EQ(pd.type, PuffData::Type::kLiterals);
  178. ASSERT_EQ(pd.length, 3);
  179. ASSERT_TRUE(pd.read_fn(tmp3, 3));
  180. ASSERT_FALSE(pd.read_fn(tmp3, 1));
  181. ASSERT_EQ(0, memcmp(tmp3, tmp, 3));
  182. }
  183. {
  184. PuffData pd;
  185. ASSERT_TRUE(pr.GetNext(&pd));
  186. ASSERT_EQ(pd.type, PuffData::Type::kLiterals);
  187. ASSERT_EQ(pd.length, 1);
  188. ASSERT_TRUE(pd.read_fn(tmp3, 1));
  189. ASSERT_EQ(tmp3[0], 10);
  190. ASSERT_FALSE(pd.read_fn(tmp3, 2));
  191. }
  192. {
  193. PuffData pd;
  194. pd.type = PuffData::Type::kEndOfBlock;
  195. ASSERT_TRUE(pw.Insert(pd));
  196. ASSERT_TRUE(epw.Insert(pd));
  197. ASSERT_TRUE(pw.Flush());
  198. ASSERT_TRUE(epw.Flush());
  199. }
  200. {
  201. PuffData pd;
  202. ASSERT_TRUE(pr.GetNext(&pd));
  203. ASSERT_EQ(pd.type, PuffData::Type::kEndOfBlock);
  204. }
  205. ASSERT_EQ(buf.size() - pr.BytesLeft(), pw.Size());
  206. ASSERT_EQ(buf.size() - pr.BytesLeft(), epw.Size());
  207. }
  208. // Testing metadata boundary.
  209. TEST(PuffIOTest, MetadataBoundaryTest) {
  210. PuffData pd;
  211. Buffer buf(3);
  212. BufferPuffWriter pw(buf.data(), buf.size());
  213. // Block metadata takes two + varied bytes, so on a thre byte buffer, only one
  214. // bytes is left for the varied part of metadata.
  215. pd.type = PuffData::Type::kBlockMetadata;
  216. pd.length = 2;
  217. ASSERT_FALSE(pw.Insert(pd));
  218. pd.length = 0; // length should be at least 1.
  219. ASSERT_FALSE(pw.Insert(pd));
  220. pd.length = 1;
  221. ASSERT_TRUE(pw.Insert(pd));
  222. Buffer puff_buffer = {0x00, 0x03, 0x02, 0x00, 0x00};
  223. BufferPuffReader pr(puff_buffer.data(), puff_buffer.size());
  224. ASSERT_FALSE(pr.GetNext(&pd));
  225. }
  226. TEST(PuffIOTest, InvalidCopyLengthsDistanceTest) {
  227. PuffData pd;
  228. Buffer puff_buffer(20);
  229. BufferPuffWriter pw(puff_buffer.data(), puff_buffer.size());
  230. // Invalid Lenght values.
  231. pd.type = PuffData::Type::kLenDist;
  232. pd.distance = 1;
  233. pd.length = 0;
  234. EXPECT_FALSE(pw.Insert(pd));
  235. pd.length = 1;
  236. EXPECT_FALSE(pw.Insert(pd));
  237. pd.length = 2;
  238. EXPECT_FALSE(pw.Insert(pd));
  239. pd.length = 3;
  240. EXPECT_TRUE(pw.Insert(pd));
  241. pd.length = 259;
  242. EXPECT_FALSE(pw.Insert(pd));
  243. pd.length = 258;
  244. EXPECT_TRUE(pw.Insert(pd));
  245. // Invalid distance values.
  246. pd.length = 3;
  247. pd.distance = 0;
  248. EXPECT_FALSE(pw.Insert(pd));
  249. pd.distance = 1;
  250. EXPECT_TRUE(pw.Insert(pd));
  251. pd.distance = 32769;
  252. EXPECT_FALSE(pw.Insert(pd));
  253. pd.distance = 32768;
  254. EXPECT_TRUE(pw.Insert(pd));
  255. // First three bytes header, four bytes value lit/len, and four bytes
  256. // invalid lit/len.
  257. puff_buffer = {0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00,
  258. 0x00, 0xFF, 0x82, 0x00, 0x00};
  259. BufferPuffReader pr(puff_buffer.data(), puff_buffer.size());
  260. EXPECT_TRUE(pr.GetNext(&pd));
  261. EXPECT_EQ(pd.type, PuffData::Type::kBlockMetadata);
  262. EXPECT_TRUE(pr.GetNext(&pd));
  263. EXPECT_EQ(pd.type, PuffData::Type::kLenDist);
  264. EXPECT_FALSE(pr.GetNext(&pd));
  265. }
  266. TEST(PuffIOTest, InvalidCopyLenghtDistanceBoundaryTest) {
  267. PuffData pd;
  268. Buffer puff_buffer(5);
  269. pd.type = PuffData::Type::kLenDist;
  270. pd.distance = 1;
  271. pd.length = 129;
  272. for (size_t i = 1; i < 2; i++) {
  273. BufferPuffWriter pw(puff_buffer.data(), i);
  274. EXPECT_FALSE(pw.Insert(pd));
  275. }
  276. pd.length = 130;
  277. for (size_t i = 1; i < 3; i++) {
  278. BufferPuffWriter pw(puff_buffer.data(), i);
  279. EXPECT_FALSE(pw.Insert(pd));
  280. }
  281. // First three bytes header, three bytes value lit/len.
  282. puff_buffer = {0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00};
  283. BufferPuffReader pr(puff_buffer.data(), puff_buffer.size());
  284. EXPECT_TRUE(pr.GetNext(&pd));
  285. EXPECT_EQ(pd.type, PuffData::Type::kBlockMetadata);
  286. EXPECT_FALSE(pr.GetNext(&pd));
  287. }
  288. TEST(PuffIOTest, LiteralsTest) {
  289. TestLiteralLength(0);
  290. TestLiteralLength(1);
  291. TestLiteralLength(2);
  292. TestLiteralLength(126);
  293. TestLiteralLength(127);
  294. TestLiteralLength(128);
  295. }
  296. // Testing maximum literals length.
  297. TEST(PuffIOTest, MaxLiteralsTest) {
  298. Buffer buf((1 << 16) + 127 + 20);
  299. PuffData pd;
  300. BufferPuffWriter pw(buf.data(), buf.size());
  301. // We need to insert a metadata otherwise it will fail.
  302. pd.type = PuffData::Type::kBlockMetadata;
  303. pd.length = 1;
  304. ASSERT_TRUE(pw.Insert(pd));
  305. pd.type = PuffData::Type::kLiterals;
  306. pd.length = (1 << 16);
  307. pd.read_fn = [](uint8_t* buffer, size_t count) {
  308. std::fill(buffer, buffer + count, 10);
  309. return true;
  310. };
  311. ASSERT_TRUE(pw.Insert(pd));
  312. ASSERT_TRUE(pw.Flush());
  313. BufferPuffReader pr(buf.data(), buf.size());
  314. ASSERT_TRUE(pr.GetNext(&pd));
  315. ASSERT_EQ(pd.type, PuffData::Type::kBlockMetadata);
  316. ASSERT_EQ(pd.length, 1);
  317. ASSERT_TRUE(pr.GetNext(&pd));
  318. ASSERT_EQ(pd.type, PuffData::Type::kLiterals);
  319. ASSERT_EQ(pd.length, 1 << 16);
  320. for (size_t i = 0; i < pd.length; i++) {
  321. uint8_t byte;
  322. pd.read_fn(&byte, 1);
  323. ASSERT_EQ(byte, 10);
  324. }
  325. BufferPuffWriter pw2(buf.data(), buf.size());
  326. pd.type = PuffData::Type::kBlockMetadata;
  327. pd.length = 1;
  328. ASSERT_TRUE(pw2.Insert(pd));
  329. pd.type = PuffData::Type::kLiteral;
  330. pd.length = 1;
  331. pd.byte = 12;
  332. // We have to be able to fill 65663 bytes.
  333. for (size_t i = 0; i < ((1 << 16) + 127); i++) {
  334. ASSERT_TRUE(pw2.Insert(pd));
  335. }
  336. // If we add one more, then it should have been flushed.
  337. pd.byte = 13;
  338. ASSERT_TRUE(pw2.Insert(pd));
  339. ASSERT_TRUE(pw2.Flush());
  340. // Now read it back.
  341. BufferPuffReader pr2(buf.data(), buf.size());
  342. ASSERT_TRUE(pr2.GetNext(&pd));
  343. ASSERT_EQ(pd.type, PuffData::Type::kBlockMetadata);
  344. // Now we should read on kLiterals with lenght 1 << 16 and just one literal
  345. // after that.
  346. ASSERT_TRUE(pr2.GetNext(&pd));
  347. ASSERT_EQ(pd.type, PuffData::Type::kLiterals);
  348. ASSERT_EQ(pd.length, (1 << 16) + 127);
  349. for (size_t i = 0; i < pd.length; i++) {
  350. uint8_t byte;
  351. pd.read_fn(&byte, 1);
  352. ASSERT_EQ(byte, 12);
  353. }
  354. ASSERT_TRUE(pr2.GetNext(&pd));
  355. ASSERT_EQ(pd.type, PuffData::Type::kLiterals);
  356. ASSERT_EQ(pd.length, 1);
  357. uint8_t byte;
  358. pd.read_fn(&byte, 1);
  359. ASSERT_EQ(byte, 13);
  360. }
  361. } // namespace puffin