github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/common/bitutil/compress_test.go (about) 1 package bitutil 2 3 import ( 4 "bytes" 5 "math/rand" 6 "testing" 7 8 "github.com/quickchainproject/quickchain/common/hexutil" 9 ) 10 11 // Tests that data bitset encoding and decoding works and is bijective. 12 func TestEncodingCycle(t *testing.T) { 13 tests := []string{ 14 // Tests generated by go-fuzz to maximize code coverage 15 "0x000000000000000000", 16 "0xef0400", 17 "0xdf7070533534333636313639343638373532313536346c1bc33339343837313070706336343035336336346c65fefb3930393233383838ac2f65fefb", 18 "0x7b64000000", 19 "0x000034000000000000", 20 "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0000000000000000000", 21 "0x4912385c0e7b64000000", 22 "0x000034000000000000000000000000000000", 23 "0x00", 24 "0x000003e834ff7f0000", 25 "0x0000", 26 "0x0000000000000000000000000000000000000000000000000000000000ff00", 27 "0x895f0c6a020f850c6a020f85f88df88d", 28 "0xdf7070533534333636313639343638373432313536346c1bc3315aac2f65fefb", 29 "0x0000000000", 30 "0xdf70706336346c65fefb", 31 "0x00006d643634000000", 32 "0xdf7070533534333636313639343638373532313536346c1bc333393438373130707063363430353639343638373532313536346c1bc333393438336336346c65fe", 33 } 34 for i, tt := range tests { 35 data := hexutil.MustDecode(tt) 36 37 proc, err := bitsetDecodeBytes(bitsetEncodeBytes(data), len(data)) 38 if err != nil { 39 t.Errorf("test %d: failed to decompress compressed data: %v", i, err) 40 continue 41 } 42 if !bytes.Equal(data, proc) { 43 t.Errorf("test %d: compress/decompress mismatch: have %x, want %x", i, proc, data) 44 } 45 } 46 } 47 48 // Tests that data bitset decoding and rencoding works and is bijective. 49 func TestDecodingCycle(t *testing.T) { 50 tests := []struct { 51 size int 52 input string 53 fail error 54 }{ 55 {size: 0, input: "0x"}, 56 57 // Crashers generated by go-fuzz 58 {size: 0, input: "0x0020", fail: errUnreferencedData}, 59 {size: 0, input: "0x30", fail: errUnreferencedData}, 60 {size: 1, input: "0x00", fail: errUnreferencedData}, 61 {size: 2, input: "0x07", fail: errMissingData}, 62 {size: 1024, input: "0x8000", fail: errZeroContent}, 63 64 // Tests generated by go-fuzz to maximize code coverage 65 {size: 29490, input: "0x343137343733323134333839373334323073333930783e3078333930783e70706336346c65303e", fail: errMissingData}, 66 {size: 59395, input: "0x00", fail: errUnreferencedData}, 67 {size: 52574, input: "0x70706336346c65c0de", fail: errExceededTarget}, 68 {size: 42264, input: "0x07", fail: errMissingData}, 69 {size: 52, input: "0xa5045bad48f4", fail: errExceededTarget}, 70 {size: 52574, input: "0xc0de", fail: errMissingData}, 71 {size: 52574, input: "0x"}, 72 {size: 29490, input: "0x34313734373332313433383937333432307333393078073034333839373334323073333930783e3078333937333432307333393078073061333930783e70706336346c65303e", fail: errMissingData}, 73 {size: 29491, input: "0x3973333930783e30783e", fail: errMissingData}, 74 75 {size: 1024, input: "0x808080608080"}, 76 {size: 1024, input: "0x808470705e3632383337363033313434303137393130306c6580ef46806380635a80"}, 77 {size: 1024, input: "0x8080808070"}, 78 {size: 1024, input: "0x808070705e36346c6580ef46806380635a80"}, 79 {size: 1024, input: "0x80808046802680"}, 80 {size: 1024, input: "0x4040404035"}, 81 {size: 1024, input: "0x4040bf3ba2b3f684402d353234373438373934409fe5b1e7ada94ebfd7d0505e27be4035"}, 82 {size: 1024, input: "0x404040bf3ba2b3f6844035"}, 83 {size: 1024, input: "0x40402d35323437343837393440bfd7d0505e27be4035"}, 84 } 85 for i, tt := range tests { 86 data := hexutil.MustDecode(tt.input) 87 88 orig, err := bitsetDecodeBytes(data, tt.size) 89 if err != tt.fail { 90 t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.fail) 91 } 92 if err != nil { 93 continue 94 } 95 if comp := bitsetEncodeBytes(orig); !bytes.Equal(comp, data) { 96 t.Errorf("test %d: decompress/compress mismatch: have %x, want %x", i, comp, data) 97 } 98 } 99 } 100 101 // TestCompression tests that compression works by returning either the bitset 102 // encoded input, or the actual input if the bitset version is longer. 103 func TestCompression(t *testing.T) { 104 // Check the the compression returns the bitset encoding is shorter 105 in := hexutil.MustDecode("0x4912385c0e7b64000000") 106 out := hexutil.MustDecode("0x80fe4912385c0e7b64") 107 108 if data := CompressBytes(in); !bytes.Equal(data, out) { 109 t.Errorf("encoding mismatch for sparse data: have %x, want %x", data, out) 110 } 111 if data, err := DecompressBytes(out, len(in)); err != nil || !bytes.Equal(data, in) { 112 t.Errorf("decoding mismatch for sparse data: have %x, want %x, error %v", data, in, err) 113 } 114 // Check the the compression returns the input if the bitset encoding is longer 115 in = hexutil.MustDecode("0xdf7070533534333636313639343638373532313536346c1bc33339343837313070706336343035336336346c65fefb3930393233383838ac2f65fefb") 116 out = hexutil.MustDecode("0xdf7070533534333636313639343638373532313536346c1bc33339343837313070706336343035336336346c65fefb3930393233383838ac2f65fefb") 117 118 if data := CompressBytes(in); !bytes.Equal(data, out) { 119 t.Errorf("encoding mismatch for dense data: have %x, want %x", data, out) 120 } 121 if data, err := DecompressBytes(out, len(in)); err != nil || !bytes.Equal(data, in) { 122 t.Errorf("decoding mismatch for dense data: have %x, want %x, error %v", data, in, err) 123 } 124 // Check that decompressing a longer input than the target fails 125 if _, err := DecompressBytes([]byte{0xc0, 0x01, 0x01}, 2); err != errExceededTarget { 126 t.Errorf("decoding error mismatch for long data: have %v, want %v", err, errExceededTarget) 127 } 128 } 129 130 // Crude benchmark for compressing random slices of bytes. 131 func BenchmarkEncoding1KBVerySparse(b *testing.B) { benchmarkEncoding(b, 1024, 0.0001) } 132 func BenchmarkEncoding2KBVerySparse(b *testing.B) { benchmarkEncoding(b, 2048, 0.0001) } 133 func BenchmarkEncoding4KBVerySparse(b *testing.B) { benchmarkEncoding(b, 4096, 0.0001) } 134 135 func BenchmarkEncoding1KBSparse(b *testing.B) { benchmarkEncoding(b, 1024, 0.001) } 136 func BenchmarkEncoding2KBSparse(b *testing.B) { benchmarkEncoding(b, 2048, 0.001) } 137 func BenchmarkEncoding4KBSparse(b *testing.B) { benchmarkEncoding(b, 4096, 0.001) } 138 139 func BenchmarkEncoding1KBDense(b *testing.B) { benchmarkEncoding(b, 1024, 0.1) } 140 func BenchmarkEncoding2KBDense(b *testing.B) { benchmarkEncoding(b, 2048, 0.1) } 141 func BenchmarkEncoding4KBDense(b *testing.B) { benchmarkEncoding(b, 4096, 0.1) } 142 143 func BenchmarkEncoding1KBSaturated(b *testing.B) { benchmarkEncoding(b, 1024, 0.5) } 144 func BenchmarkEncoding2KBSaturated(b *testing.B) { benchmarkEncoding(b, 2048, 0.5) } 145 func BenchmarkEncoding4KBSaturated(b *testing.B) { benchmarkEncoding(b, 4096, 0.5) } 146 147 func benchmarkEncoding(b *testing.B, bytes int, fill float64) { 148 // Generate a random slice of bytes to compress 149 random := rand.NewSource(0) // reproducible and comparable 150 151 data := make([]byte, bytes) 152 bits := int(float64(bytes) * 8 * fill) 153 154 for i := 0; i < bits; i++ { 155 idx := random.Int63() % int64(len(data)) 156 bit := uint(random.Int63() % 8) 157 data[idx] |= 1 << bit 158 } 159 // Reset the benchmark and measure encoding/decoding 160 b.ResetTimer() 161 b.ReportAllocs() 162 for i := 0; i < b.N; i++ { 163 bitsetDecodeBytes(bitsetEncodeBytes(data), len(data)) 164 } 165 }