diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/tlzss.nim | 9 | ||||
-rw-r--r-- | tests/tlzsshuffman.nim | 144 |
2 files changed, 144 insertions, 9 deletions
diff --git a/tests/tlzss.nim b/tests/tlzss.nim index 7325d5b..b6b3c51 100644 --- a/tests/tlzss.nim +++ b/tests/tlzss.nim | |||
@@ -66,15 +66,6 @@ suite "lzsschain": | |||
66 | test "decode": | 66 | test "decode": |
67 | check chain().decode() == @[0'u8, 1, 2, 3, 4, 5, 0, 1, 2, 3, 0, 1, 4, 5, 0, 5, 5, 0, 5, 5] | 67 | check chain().decode() == @[0'u8, 1, 2, 3, 4, 5, 0, 1, 2, 3, 0, 1, 4, 5, 0, 5, 5, 0, 5, 5] |
68 | 68 | ||
69 | test "stats": | ||
70 | let stats = chain().stats() | ||
71 | check stats.characters == newCountTable(concat( | ||
72 | repeat(0'u8, 2), repeat(1'u8, 2), repeat(2'u8, 1), repeat(3'u8, 1), repeat(4'u8, 1), repeat(5'u8, 3))) | ||
73 | check stats.lengths == newCountTable(concat( | ||
74 | repeat(3, 2), repeat(4, 1))) | ||
75 | check stats.positions == newCountTable(concat( | ||
76 | repeat(3, 1), repeat(6, 1), repeat(8, 1))) | ||
77 | |||
78 | suite "lzssencoder": | 69 | suite "lzssencoder": |
79 | test "commonPrefixLength": | 70 | test "commonPrefixLength": |
80 | check commonPrefixLength([], [], 0, 10) == 0 | 71 | check commonPrefixLength([], [], 0, 10) == 0 |
diff --git a/tests/tlzsshuffman.nim b/tests/tlzsshuffman.nim new file mode 100644 index 0000000..f771f31 --- /dev/null +++ b/tests/tlzsshuffman.nim | |||
@@ -0,0 +1,144 @@ | |||
1 | # gzip-like LZSS compressor | ||
2 | # Copyright (C) 2018 Pacien TRAN-GIRARD | ||
3 | # | ||
4 | # This program is free software: you can redistribute it and/or modify | ||
5 | # it under the terms of the GNU Affero General Public License as | ||
6 | # published by the Free Software Foundation, either version 3 of the | ||
7 | # License, or (at your option) any later version. | ||
8 | # | ||
9 | # This program is distributed in the hope that it will be useful, | ||
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | # GNU Affero General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU Affero General Public License | ||
15 | # along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
16 | |||
17 | import unittest, tables, lists, sequtils, streams | ||
18 | import bitio/bitwriter, bitio/bitreader | ||
19 | import lzss/listpolyfill, lzss/lzssnode, lzss/lzsschain | ||
20 | import huffman/huffmantree, huffman/huffmantreebuilder, huffman/huffmanencoder, huffman/huffmandecoder | ||
21 | import lzsshuffman/lzsshuffmansymbol, lzsshuffman/lzsshuffmanstats, lzsshuffman/lzsshuffmanencoder, lzsshuffman/lzsshuffmandecoder | ||
22 | |||
23 | suite "lzsshuffmansymbol": | ||
24 | test "isEndMarker": | ||
25 | check 'a'.Symbol.isEndMarker() == false | ||
26 | check endSymbol.isEndMarker() | ||
27 | |||
28 | test "isCharacter": | ||
29 | check 'a'.Symbol.isCharacter() | ||
30 | check endSymbol.isCharacter() == false | ||
31 | check 300.Symbol.isCharacter() == false | ||
32 | |||
33 | test "unpackLzssReference": | ||
34 | check unpackLzssReference(257.Symbol, 10) == lzssReference(3, 10) | ||
35 | check unpackLzssReference(300.Symbol, 10) == lzssReference(46, 10) | ||
36 | |||
37 | test "shiftLzssLength": | ||
38 | check shiftLzssLength(3) == 257'u16 | ||
39 | check shiftLzssLength(10) == 264'u16 | ||
40 | |||
41 | suite "lzsshuffmanstats": | ||
42 | test "aggretateStats": | ||
43 | let chain = lzssChain([ | ||
44 | lzssCharacter(0), lzssCharacter(1), lzssCharacter(2), | ||
45 | lzssCharacter(3), lzssCharacter(4), lzssCharacter(5), | ||
46 | lzssReference(4, 6), lzssCharacter(0), lzssCharacter(1), | ||
47 | lzssReference(3, 8), lzssCharacter(5), | ||
48 | lzssReference(3, 3), lzssCharacter(5)]) | ||
49 | let (symbolTable, positionTable) = chain.aggregateStats() | ||
50 | check symbolTable == newCountTable(concat( | ||
51 | repeat(0'u16, 2), repeat(1'u16, 2), repeat(2'u16, 1), repeat(3'u16, 1), repeat(4'u16, 1), repeat(5'u16, 3), | ||
52 | repeat(endSymbol.uint16, 1), | ||
53 | repeat(257'u16, 2), repeat(258'u16, 1))) | ||
54 | check positionTable == newCountTable(concat( | ||
55 | repeat(3'u16, 1), repeat(6'u16, 1), repeat(8'u16, 1))) | ||
56 | |||
57 | suite "lzsshuffmanencoder": | ||
58 | test "writeChain (empty)": | ||
59 | let chain = lzssChain(newSeq[LzssNode]()) | ||
60 | let symbolTree = huffmanLeaf(endSymbol.uint16) | ||
61 | let positionTree = huffmanLeaf(0'u16) | ||
62 | let stream = newStringStream() | ||
63 | defer: stream.close() | ||
64 | let bitWriter = stream.bitWriter() | ||
65 | writeChain(chain, symbolTree.encoder(uint16), positionTree.encoder(uint16), bitWriter) | ||
66 | bitWriter.flush() | ||
67 | stream.setPosition(0) | ||
68 | check stream.atEnd() | ||
69 | |||
70 | test "writeChain (minimal)": | ||
71 | let chain = lzssChain([ | ||
72 | lzssCharacter(0), lzssCharacter(1), lzssCharacter(2), | ||
73 | lzssReference(3, 3), lzssReference(3, 4)]) | ||
74 | let symbolTree = huffmanBranch( | ||
75 | huffmanBranch( | ||
76 | huffmanLeaf(0'u16), | ||
77 | huffmanLeaf(1'u16)), | ||
78 | huffmanBranch( | ||
79 | huffmanLeaf(257'u16), | ||
80 | huffmanBranch( | ||
81 | huffmanLeaf(2'u16), | ||
82 | huffmanLeaf(256'u16)))) | ||
83 | let positionTree = huffmanBranch( | ||
84 | huffmanLeaf(3'u16), | ||
85 | huffmanLeaf(4'u16)) | ||
86 | let stream = newStringStream() | ||
87 | defer: stream.close() | ||
88 | let bitWriter = stream.bitWriter() | ||
89 | writeChain(chain, symbolTree.encoder(uint16), positionTree.encoder(uint16), bitWriter) | ||
90 | bitWriter.flush() | ||
91 | stream.setPosition(0) | ||
92 | let bitReader = stream.bitReader() | ||
93 | check bitReader.readBits(2, uint8) == 0b00'u8 # char 0 | ||
94 | check bitReader.readBits(2, uint8) == 0b10'u8 # char 1 | ||
95 | check bitReader.readBits(3, uint8) == 0b011'u8 # char 2 | ||
96 | check bitReader.readBits(2, uint8) == 0b01'u8 # ref len 3 | ||
97 | check bitReader.readBits(1, uint8) == 0b0'u8 # ref pos 3 | ||
98 | check bitReader.readBits(2, uint8) == 0b01'u8 # ref len 3 | ||
99 | check bitReader.readBits(1, uint8) == 0b1'u8 # ref pos 4 | ||
100 | check bitReader.readBits(3, uint8) == 0b111'u8 # eof | ||
101 | |||
102 | suite "lzsshuffmandecoder": | ||
103 | test "readChain (empty)": | ||
104 | let symbolTree = huffmanLeaf(endSymbol.uint16) | ||
105 | let positionTree = huffmanLeaf(0'u16) | ||
106 | let stream = newStringStream() | ||
107 | defer: stream.close() | ||
108 | stream.write(0'u8) # eof | ||
109 | stream.setPosition(0) | ||
110 | let bitReader = stream.bitReader() | ||
111 | let result = readChain(bitReader, symbolTree.decoder(), positionTree.decoder(), 32_000) | ||
112 | check toSeq(result.items).len == 0 | ||
113 | |||
114 | test "readChain (minimal)": | ||
115 | let symbolTree = huffmanBranch( | ||
116 | huffmanBranch( | ||
117 | huffmanLeaf(0'u16), | ||
118 | huffmanLeaf(1'u16)), | ||
119 | huffmanBranch( | ||
120 | huffmanLeaf(257'u16), | ||
121 | huffmanBranch( | ||
122 | huffmanLeaf(2'u16), | ||
123 | huffmanLeaf(256'u16)))) | ||
124 | let positionTree = huffmanBranch( | ||
125 | huffmanLeaf(3'u16), | ||
126 | huffmanLeaf(4'u16)) | ||
127 | let stream = newStringStream() | ||
128 | defer: stream.close() | ||
129 | let bitWriter = stream.bitWriter() | ||
130 | bitWriter.writeBits(2, 0b00'u8) | ||
131 | bitWriter.writeBits(2, 0b10'u8) | ||
132 | bitWriter.writeBits(3, 0b011'u8) | ||
133 | bitWriter.writeBits(2, 0b01'u8) | ||
134 | bitWriter.writeBits(1, 0b0'u8) | ||
135 | bitWriter.writeBits(2, 0b01'u8) | ||
136 | bitWriter.writeBits(1, 0b1'u8) | ||
137 | bitWriter.writeBits(3, 0b111'u8) | ||
138 | bitWriter.flush() | ||
139 | stream.setPosition(0) | ||
140 | let bitReader = stream.bitReader() | ||
141 | let result = readChain(bitReader, symbolTree.decoder(), positionTree.decoder(), 32_000) | ||
142 | check toSeq(result.items) == [ | ||
143 | lzssCharacter(0), lzssCharacter(1), lzssCharacter(2), | ||
144 | lzssReference(3, 3), lzssReference(3, 4)] | ||