Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The Chromium 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 | |
| 5 #include "net/tools/transport_security_state_generator/huffman/huffman_builder.h " | |
| 6 #include "testing/gmock/include/gmock/gmock.h" | |
| 7 #include "testing/gtest/include/gtest/gtest.h" | |
| 8 | |
| 9 namespace net { | |
| 10 | |
| 11 namespace transport_security_state { | |
| 12 | |
| 13 // Test that there are no Huffman representations that are a prefix for another. | |
| 14 TEST(HuffmanBuilderTest, NoPrefixCollision) { | |
| 15 HuffmanBuilder builder; | |
| 16 HuffmanRepresentationTable encoding; | |
| 17 for (uint8_t i = 0; i <= 127; i++) { | |
| 18 // Make sure some values have identical counts. | |
|
Ryan Sleevi
2017/03/30 15:03:32
Doesn't this make _most_ values have identical cou
martijnc
2017/03/30 19:02:22
The intention is to make the values have an identi
| |
| 19 for (uint8_t j = 0; j <= i % 32; j++) { | |
| 20 builder.RecordUsage(i); | |
| 21 } | |
| 22 } | |
| 23 | |
| 24 encoding = builder.ToTable(); | |
| 25 for (uint8_t i = 0; i <= 127; i++) { | |
| 26 // There should never exist a representation that is a prefix for, or | |
| 27 // identical to, another. | |
| 28 uint32_t mask = 0; | |
| 29 for (uint32_t k = 0; k <= encoding[i].number_of_bits; k++) { | |
| 30 mask = (mask << 1) | 1; | |
| 31 } | |
| 32 mask = mask << (32 - encoding[i].number_of_bits); | |
| 33 | |
| 34 for (uint8_t j = 0; j <= 127; j++) { | |
| 35 if (i == j) { | |
| 36 continue; | |
| 37 } | |
| 38 | |
| 39 uint32_t aligned_i = encoding[i].bits | |
| 40 << (32 - encoding[i].number_of_bits); | |
| 41 uint32_t aligned_j = encoding[j].bits | |
| 42 << (32 - encoding[j].number_of_bits); | |
| 43 EXPECT_NE(aligned_i, aligned_j & mask); | |
| 44 } | |
| 45 } | |
| 46 } | |
| 47 | |
| 48 // Test that all recorded characters get a representation and that no other | |
| 49 // representations are created. | |
| 50 // Note: There is an exception for encodings with less than 2 unique inputs. | |
| 51 TEST(HuffmanBuilderTest, NoMissingInputs) { | |
| 52 HuffmanBuilder builder; | |
| 53 HuffmanRepresentationTable encoding; | |
| 54 for (uint8_t i = 0; i <= 63; i++) { | |
|
Ryan Sleevi
2017/03/30 15:03:32
Why 63 (vs 127 above)? The i*2 means you'll skip 1
martijnc
2017/03/30 19:02:22
Yes, this intentionally skips over every odd value
| |
| 55 for (uint8_t j = 0; j <= i % 5; j++) { | |
| 56 builder.RecordUsage(i * 2); | |
| 57 } | |
| 58 } | |
| 59 | |
| 60 encoding = builder.ToTable(); | |
| 61 for (uint8_t i = 0; i <= 126; i++) { | |
| 62 if (i % 2) { | |
| 63 EXPECT_EQ(encoding.find(i), encoding.cend()); | |
| 64 } else { | |
| 65 EXPECT_NE(encoding.find(i), encoding.cend()); | |
| 66 } | |
| 67 } | |
| 68 } | |
| 69 | |
| 70 // Test that the representations have optimal order by checking that characters | |
| 71 // with higher counts get shorter (or equal length) representations than those | |
| 72 // with lower counts. | |
| 73 TEST(HuffmanBuilderTest, OptimalCodeOrder) { | |
| 74 HuffmanBuilder builder; | |
| 75 HuffmanRepresentationTable encoding; | |
| 76 for (uint8_t i = 0; i <= 127; i++) { | |
| 77 for (uint8_t j = 0; j <= (i + 1); j++) { | |
| 78 builder.RecordUsage(i); | |
| 79 } | |
| 80 } | |
| 81 | |
| 82 encoding = builder.ToTable(); | |
| 83 for (uint8_t i = 0; i <= 127; i++) { | |
| 84 // The representation for |i| should be longer or have the same length as | |
| 85 // all following representations because they have a higher frequency and | |
| 86 // therefor should never get a longer representation. | |
| 87 for (uint8_t j = i; j <= 127; j++) { | |
| 88 // A representation for the values should exist in the table. | |
| 89 ASSERT_NE(encoding.find(i), encoding.cend()); | |
| 90 ASSERT_NE(encoding.find(j), encoding.cend()); | |
| 91 | |
| 92 EXPECT_GE(encoding[i].number_of_bits, encoding[j].number_of_bits); | |
| 93 } | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 // Test that the ToVector() creates a byte vector that represents the expected | |
| 98 // Huffman Tree. | |
| 99 TEST(HuffmanBuilderTest, ToVector) { | |
| 100 // Build a small tree. | |
| 101 HuffmanBuilder builder; | |
| 102 builder.RecordUsage('a'); | |
| 103 builder.RecordUsage('b'); | |
| 104 builder.RecordUsage('b'); | |
| 105 builder.RecordUsage('c'); | |
| 106 builder.RecordUsage('c'); | |
| 107 builder.RecordUsage('d'); | |
| 108 builder.RecordUsage('d'); | |
| 109 builder.RecordUsage('d'); | |
| 110 builder.RecordUsage('e'); | |
| 111 builder.RecordUsage('e'); | |
| 112 builder.RecordUsage('e'); | |
| 113 | |
| 114 std::vector<uint8_t> output = builder.ToVector(); | |
| 115 | |
| 116 // This represents 4 elements (4 groups of 2 uint8_t's) which, when decoded, | |
| 117 // yields the expected Huffman Tree: | |
| 118 // root (element 3) | |
| 119 // / \ | |
| 120 // element 1 element 2 | |
| 121 // / \ / \ | |
| 122 // 0xE3 (c) element 0 0xE4 (e) 0xE5 (f) | |
| 123 // / \ | |
| 124 // 0xE1 (a) 0xE2 (b) | |
| 125 EXPECT_THAT(output, testing::ElementsAre(0xE1, 0xE2, 0xE3, 0x0, 0xE4, 0xE5, | |
| 126 0x1, 0x2)); | |
|
Ryan Sleevi
2017/03/30 15:03:32
Sleevi stupidity - why 0x1/0x2?
martijnc
2017/03/30 19:02:22
Every pair of uint8_t's represents a node in the t
| |
| 127 } | |
| 128 | |
| 129 // The ToVector() logic requires at least 2 unique inputs to construct the | |
| 130 // vector. Test that nodes are appended when there are less than 2 unique | |
| 131 // inputs. | |
| 132 TEST(HuffmanBuilderTest, ToVectorSingle) { | |
| 133 // Build a single element tree. Another element should be added automatically. | |
| 134 HuffmanBuilder builder; | |
| 135 builder.RecordUsage('a'); | |
| 136 | |
| 137 std::vector<uint8_t> output = builder.ToVector(); | |
| 138 | |
| 139 // This represents 1 elements (1 group of 2 uint8_t's) which, when decoded, | |
| 140 // yields the expected Huffman Tree: | |
| 141 // root (element 1) | |
| 142 // / \ | |
| 143 // 0x80 (\0) 0xE1 (a) | |
| 144 // | |
| 145 // Note: the node \0 node was appended to the tree. | |
| 146 EXPECT_THAT(output, testing::ElementsAre(0x80, 0xE1)); | |
| 147 } | |
| 148 | |
| 149 } // transport_security_state | |
| 150 | |
| 151 } // namespace net | |
| OLD | NEW |