From 925f8d7176c3d54d435896ec0d2eabda634bbcc8 Mon Sep 17 00:00:00 2001
From: pacien
Date: Mon, 3 Dec 2018 18:42:23 +0100
Subject: merge tests
---
tests/bitio/tbitreader.nim | 84 ++++++++++++++
tests/bitio/tbitwriter.nim | 85 +++++++++++++++
tests/bitio/tintegers.nim | 43 ++++++++
tests/blocks/trawblock.nim | 57 ++++++++++
tests/blocks/tstreamblock.nim | 68 ++++++++++++
tests/gziplike/tgziplike.nim | 40 +++++++
tests/huffman/thuffmandecoder.nim | 43 ++++++++
tests/huffman/thuffmanencoder.nim | 38 +++++++
tests/huffman/thuffmantree.nim | 75 +++++++++++++
tests/huffman/thuffmantreebuilder.nim | 30 +++++
tests/lzss/tlzsschain.nim | 29 +++++
tests/lzss/tlzssencoder.nim | 59 ++++++++++
tests/lzss/tlzssnode.nim | 26 +++++
tests/lzss/tmatchring.nim | 35 ++++++
tests/lzss/tmatchtable.nim | 29 +++++
tests/lzsshuffman/tlzsshuffmandecoder.nim | 65 +++++++++++
tests/lzsshuffman/tlzsshuffmanencoder.nim | 66 +++++++++++
tests/lzsshuffman/tlzsshuffmanstats.nim | 35 ++++++
tests/lzsshuffman/tlzsshuffmansymbol.nim | 37 +++++++
tests/tbitio.nim | 176 ------------------------------
tests/tblocks.nim | 107 ------------------
tests/tests.nim | 42 +++++++
tests/tgziplike.nim | 40 -------
tests/thuffman.nim | 119 --------------------
tests/tlzss.nim | 105 ------------------
tests/tlzsshuffman.nim | 144 ------------------------
26 files changed, 986 insertions(+), 691 deletions(-)
create mode 100644 tests/bitio/tbitreader.nim
create mode 100644 tests/bitio/tbitwriter.nim
create mode 100644 tests/bitio/tintegers.nim
create mode 100644 tests/blocks/trawblock.nim
create mode 100644 tests/blocks/tstreamblock.nim
create mode 100644 tests/gziplike/tgziplike.nim
create mode 100644 tests/huffman/thuffmandecoder.nim
create mode 100644 tests/huffman/thuffmanencoder.nim
create mode 100644 tests/huffman/thuffmantree.nim
create mode 100644 tests/huffman/thuffmantreebuilder.nim
create mode 100644 tests/lzss/tlzsschain.nim
create mode 100644 tests/lzss/tlzssencoder.nim
create mode 100644 tests/lzss/tlzssnode.nim
create mode 100644 tests/lzss/tmatchring.nim
create mode 100644 tests/lzss/tmatchtable.nim
create mode 100644 tests/lzsshuffman/tlzsshuffmandecoder.nim
create mode 100644 tests/lzsshuffman/tlzsshuffmanencoder.nim
create mode 100644 tests/lzsshuffman/tlzsshuffmanstats.nim
create mode 100644 tests/lzsshuffman/tlzsshuffmansymbol.nim
delete mode 100644 tests/tbitio.nim
delete mode 100644 tests/tblocks.nim
create mode 100644 tests/tests.nim
delete mode 100644 tests/tgziplike.nim
delete mode 100644 tests/thuffman.nim
delete mode 100644 tests/tlzss.nim
delete mode 100644 tests/tlzsshuffman.nim
(limited to 'tests')
diff --git a/tests/bitio/tbitreader.nim b/tests/bitio/tbitreader.nim
new file mode 100644
index 0000000..3949b8b
--- /dev/null
+++ b/tests/bitio/tbitreader.nim
@@ -0,0 +1,84 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, streams, sugar
+import bitio/bitreader
+
+suite "bitreader":
+ test "readBool":
+ let stream = newStringStream()
+ defer: stream.close()
+ stream.write(0b1001_1111'u8)
+ stream.write(0b0110_0000'u8)
+ stream.setPosition(0)
+
+ let bitReader = stream.bitReader()
+ check lc[bitReader.readBool() | (_ <- 0..<16), bool] == @[
+ true, true, true, true, true, false, false, true,
+ false, false, false, false, false, true, true, false]
+
+ expect IOError: discard bitReader.readBool()
+ check bitReader.atEnd()
+
+ test "readBits":
+ let stream = newStringStream()
+ defer: stream.close()
+ stream.write(0xF00F'u16)
+ stream.write(0x0FFF'u16)
+ stream.setPosition(0)
+
+ let bitReader = stream.bitReader()
+ check bitReader.readBits(8, uint8) == 0x0F'u8
+ check bitReader.readBits(16, uint16) == 0xFFF0'u16
+ check bitReader.readBits(8, uint8) == 0x0F'u8
+
+ expect RangeError: discard bitReader.readBits(9, uint8)
+ expect IOError: discard bitReader.readBits(16, uint16)
+ check bitReader.atEnd()
+
+ test "readBits (look-ahead overflow)":
+ let stream = newStringStream()
+ defer: stream.close()
+ stream.write(0xAB'u8)
+ stream.setPosition(0)
+
+ let bitReader = stream.bitReader()
+ check bitReader.readBits(4, uint16) == 0x000B'u16
+ check bitReader.readBits(4, uint16) == 0x000A'u16
+ check bitReader.atEnd()
+
+ test "readBits (from buffer composition)":
+ let stream = newStringStream()
+ defer: stream.close()
+ stream.write(0xABCD'u16)
+ stream.setPosition(0)
+
+ let bitReader = stream.bitReader()
+ check bitReader.readBits(4, uint16) == 0x000D'u16
+ check bitReader.readBits(8, uint16) == 0x00BC'u16
+ check bitReader.readBits(4, uint16) == 0x000A'u16
+ check bitReader.atEnd()
+
+ test "readSeq":
+ let stream = newStringStream()
+ defer: stream.close()
+ stream.write(0x0F00_F0FF_F0F0_F0F0'u64)
+ stream.setPosition(0)
+
+ let bitReader = stream.bitReader()
+ check bitReader.readSeq(32, uint16) == (32, @[0xF0F0'u16, 0xF0F0])
+ check bitReader.readSeq(40, uint8) == (32, @[0xFF'u8, 0xF0, 0x00, 0x0F])
+ check bitReader.atEnd()
diff --git a/tests/bitio/tbitwriter.nim b/tests/bitio/tbitwriter.nim
new file mode 100644
index 0000000..70f5a1b
--- /dev/null
+++ b/tests/bitio/tbitwriter.nim
@@ -0,0 +1,85 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, streams
+import bitio/bitwriter
+
+suite "bitwriter":
+ test "flush":
+ let stream = newStringStream()
+ defer: stream.close()
+ let bitWriter = stream.bitWriter()
+
+ bitWriter.writeBool(true)
+ stream.setPosition(0)
+ expect IOError: discard stream.peekUint8()
+
+ bitWriter.flush()
+ stream.setPosition(0)
+ check stream.readUint8() == 0x01'u8
+ check stream.atEnd()
+
+ bitWriter.flush()
+ check stream.atEnd()
+
+ test "writeBool":
+ let stream = newStringStream()
+ defer: stream.close()
+
+ let bitWriter = stream.bitWriter()
+ let booleanValues = @[
+ true, true, true, true, true, false, false, true,
+ false, false, false, false, false, true, true, false,
+ true, true, false, true]
+ for b in booleanValues: bitWriter.writeBool(b)
+ bitWriter.flush()
+
+ stream.setPosition(0)
+ check stream.readUint8() == 0b1001_1111'u8
+ check stream.readUint8() == 0b0110_0000'u8
+ check stream.readUint8() == 0b0000_1011'u8
+ expect IOError: discard stream.readUint8()
+ check stream.atEnd()
+
+ test "writeBits":
+ let stream = newStringStream()
+ defer: stream.close()
+
+ let bitWriter = stream.bitWriter()
+ bitWriter.writeBits(4, 0xF00F'u16)
+ bitWriter.writeBits(16, 0xF00F'u16)
+ bitWriter.writeBits(16, 0xFFFF'u16)
+ bitWriter.flush()
+
+ stream.setPosition(0)
+ check stream.readUint16() == 0x00FF'u16
+ check stream.readUint16() == 0xFFFF'u16
+ check stream.readUint8() == 0x0F'u8
+ expect IOError: discard stream.readUint8()
+ check stream.atEnd()
+
+ test "writeSeq":
+ let stream = newStringStream()
+ defer: stream.close()
+
+ let bitWriter = stream.bitWriter()
+ bitWriter.writeSeq(32, @[0xF0F0'u16, 0xF0F0])
+ bitWriter.writeSeq(28, @[0xFF'u8, 0xF0, 0x00, 0xFF])
+ bitWriter.flush()
+
+ stream.setPosition(0)
+ check stream.readUint64() == 0x0F00_F0FF_F0F0_F0F0'u64
+ check stream.atEnd()
diff --git a/tests/bitio/tintegers.nim b/tests/bitio/tintegers.nim
new file mode 100644
index 0000000..e17a2ac
--- /dev/null
+++ b/tests/bitio/tintegers.nim
@@ -0,0 +1,43 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, sequtils
+import bitio/integers
+
+suite "integers":
+ test "Round-up integer division":
+ check 42 /^ 2 == 21
+ check 43 /^ 2 == 22
+
+ test "truncateToUint8":
+ check truncateToUint8(0xFA'u8) == 0xFA'u8
+ check truncateToUint8(0x00FA'u16) == 0xFA'u8
+ check truncateToUint8(0xFFFA'u16) == 0xFA'u8
+
+ test "bitLength":
+ check bitLength(0b1_1111) == 5
+ check bitLength(0b1000_0000) == 8
+
+ test "leastSignificantBits":
+ check leastSignificantBits(0xFF'u8, 3) == 0b0000_0111'u8
+ check leastSignificantBits(0b0001_0101'u8, 3) == 0b0000_0101'u8
+ check leastSignificantBits(0xFF'u8, 10) == 0xFF'u8
+ check leastSignificantBits(0xFFFF'u16, 16) == 0xFFFF'u16
+ check leastSignificantBits(0xFFFF'u16, 8) == 0x00FF'u16
+
+ test "chunks iterator":
+ check toSeq(chunks(70, uint32)) == @[(0, 32), (1, 32), (2, 6)]
+ check toSeq(chunks(32, uint16)) == @[(0, 16), (1, 16)]
diff --git a/tests/blocks/trawblock.nim b/tests/blocks/trawblock.nim
new file mode 100644
index 0000000..2426899
--- /dev/null
+++ b/tests/blocks/trawblock.nim
@@ -0,0 +1,57 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, streams
+import bitio/bitreader, bitio/bitwriter, blocks/rawblock
+
+suite "rawblock":
+ test "serialise":
+ let rawStream = newStringStream()
+ defer: rawStream.close()
+ rawStream.write(0xFEDC_BA98_7654_3210'u64)
+ rawStream.setPosition(0)
+ let rawBitReader = rawStream.bitReader()
+ let rawBlock = rawblock.readRaw(rawBitReader)
+
+ let outputStream = newStringStream()
+ defer: outputStream.close()
+ let outputBitWriter = outputStream.bitWriter()
+ rawBlock.writeSerialisedTo(outputBitWriter)
+ outputBitWriter.flush()
+
+ outputStream.setPosition(0)
+ check outputStream.readUint16() == 64
+ check outputStream.readUint64() == 0xFEDC_BA98_7654_3210'u64
+ check outputStream.atEnd()
+
+ test "deserialise":
+ let serialisedStream = newStringStream()
+ defer: serialisedStream.close()
+ serialisedStream.write(60'u16)
+ serialisedStream.write(0xFEDC_BA98_7654_3210'u64)
+ serialisedStream.setPosition(0)
+ let serialisedBitReader = serialisedStream.bitReader()
+ let rawBlock = rawBlock.readSerialised(serialisedBitReader)
+
+ let outputStream = newStringStream()
+ defer: outputStream.close()
+ let outputBitWriter = outputStream.bitWriter()
+ rawBlock.writeRawTo(outputBitWriter)
+ outputBitWriter.flush()
+
+ outputStream.setPosition(0)
+ check outputStream.readUint64 == 0x0EDC_BA98_7654_3210'u64
+ check outputStream.atEnd()
diff --git a/tests/blocks/tstreamblock.nim b/tests/blocks/tstreamblock.nim
new file mode 100644
index 0000000..4d92d69
--- /dev/null
+++ b/tests/blocks/tstreamblock.nim
@@ -0,0 +1,68 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, streams
+import bitio/bitreader, bitio/bitwriter, blocks/streamblock
+
+suite "streamblock":
+ test "serialise":
+ let rawStream = newStringStream()
+ defer: rawStream.close()
+ rawStream.write(0xFEDC_BA98_7654_3210'u64)
+ rawStream.setPosition(0)
+ let rawBitReader = rawStream.bitReader()
+ let streamBlock = readRaw(rawBitReader, uncompressed)
+ check streamBlock.isLast()
+
+ let outputStream = newStringStream()
+ defer: outputStream.close()
+ let outputBitWriter = outputStream.bitWriter()
+ streamBlock.writeSerialisedTo(outputBitWriter)
+ outputBitWriter.flush()
+
+ outputStream.setPosition(0)
+ let produceReader = outputStream.bitReader()
+ check produceReader.readBool() == true # last block flag
+ check produceReader.readBits(2, uint8) == 0x00'u8 # block kind
+ check produceReader.readBits(16, uint16) == 64 # raw block length
+ check produceReader.readSeq(64, uint8) == (64, @[0x10'u8, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE]) # raw block content
+ discard produceReader.readBits(8 - 2 - 1, uint8)
+ check produceReader.atEnd()
+
+ test "deserialise":
+ let serialisedStream = newStringStream()
+ defer: serialisedStream.close()
+ let serialisedBitWriter = serialisedStream.bitWriter()
+ serialisedBitWriter.writeBool(true)
+ serialisedBitWriter.writeBits(2, 0x00'u8)
+ serialisedBitWriter.writeBits(16, 64'u16)
+ serialisedBitWriter.writeBits(64, 0xFEDC_BA98_7654_3210'u64)
+ serialisedBitWriter.flush()
+
+ serialisedStream.setPosition(0)
+ let serialisedBitReader = serialisedStream.bitReader()
+ let streamBlock = streamblock.readSerialised(serialisedBitReader)
+
+ let outputStream = newStringStream()
+ defer: outputStream.close()
+ let outputBitWriter = outputStream.bitWriter()
+ check streamBlock.isLast()
+ streamBlock.writeRawTo(outputBitWriter)
+ outputBitWriter.flush()
+
+ outputStream.setPosition(0)
+ check outputStream.readUint64 == 0xFEDC_BA98_7654_3210'u64
+ check outputStream.atEnd()
diff --git a/tests/gziplike/tgziplike.nim b/tests/gziplike/tgziplike.nim
new file mode 100644
index 0000000..b26a453
--- /dev/null
+++ b/tests/gziplike/tgziplike.nim
@@ -0,0 +1,40 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, os, ospaths, osproc, times
+import gziplike
+
+suite "main":
+ const tempDir = "tmp"
+
+ proc testIdentity(input: string, intermediate = tempDir / "compressed", final = tempDir / "decompressed"): bool =
+ let compressionStartTime = getTime()
+ compress.transform(input, intermediate)
+ echo("compression done in ", getTime() - compressionStartTime)
+ echo("compression ratio: ", (intermediate.getFileSize() * 100) div input.getFileSize(), "%")
+ let decompressionStartTime = getTime()
+ decompress.transform(intermediate, final)
+ echo("decompression done in ", getTime() - decompressionStartTime)
+ startProcess("cmp", args=[input, final], options={poUsePath}).waitForExit() == 0
+
+ setup: createDir(tempDir)
+ teardown: removeDir(tempDir)
+
+ test "identity (text)":
+ check testIdentity("license.md")
+
+ test "identity (binary)":
+ check testIdentity("tests" / "tests")
diff --git a/tests/huffman/thuffmandecoder.nim b/tests/huffman/thuffmandecoder.nim
new file mode 100644
index 0000000..44fad64
--- /dev/null
+++ b/tests/huffman/thuffmandecoder.nim
@@ -0,0 +1,43 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, streams
+import bitio/bitreader, bitio/bitwriter
+import huffman/huffmantree, huffman/huffmandecoder
+
+suite "huffmandecoder":
+ let tree = huffmanBranch(
+ huffmanLeaf(1'u),
+ huffmanBranch(
+ huffmanLeaf(2'u),
+ huffmanLeaf(3'u)))
+
+ test "decode":
+ let stream = newStringStream()
+ defer: stream.close()
+ let bitWriter = stream.bitWriter()
+ bitWriter.writeBool(true) # 2
+ bitWriter.writeBool(false)
+ bitWriter.writeBool(false) # 1
+ bitWriter.writeBool(true) # 3
+ bitWriter.writeBool(true)
+ bitWriter.flush()
+ stream.setPosition(0)
+ let bitReader = stream.bitReader()
+ let decoder = tree.decoder()
+ check decoder.decode(bitReader) == 2'u
+ check decoder.decode(bitReader) == 1'u
+ check decoder.decode(bitReader) == 3'u
diff --git a/tests/huffman/thuffmanencoder.nim b/tests/huffman/thuffmanencoder.nim
new file mode 100644
index 0000000..d08db03
--- /dev/null
+++ b/tests/huffman/thuffmanencoder.nim
@@ -0,0 +1,38 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, tables
+import huffman/huffmantree, huffman/huffmanencoder
+
+suite "huffmanencoder":
+ let tree = huffmanBranch(
+ huffmanLeaf(1'u),
+ huffmanBranch(
+ huffmanLeaf(2'u),
+ huffmanLeaf(3'u)))
+
+ test "buildCodebook":
+ let codebook = buildCodebook(tree, uint)
+ check codebook.len == 3
+ check codebook[1'u] == (1, 0b0'u)
+ check codebook[2'u] == (2, 0b01'u)
+ check codebook[3'u] == (2, 0b11'u)
+
+ test "encode":
+ let encoder = tree.encoder(uint)
+ check encoder.encode(1'u) == (1, 0b0'u)
+ check encoder.encode(2'u) == (2, 0b01'u)
+ check encoder.encode(3'u) == (2, 0b11'u)
diff --git a/tests/huffman/thuffmantree.nim b/tests/huffman/thuffmantree.nim
new file mode 100644
index 0000000..ac8fa59
--- /dev/null
+++ b/tests/huffman/thuffmantree.nim
@@ -0,0 +1,75 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, streams
+import bitio/bitreader, bitio/bitwriter
+import huffman/huffmantree
+
+suite "huffmantree":
+ let tree = huffmanBranch(
+ huffmanLeaf(1'u),
+ huffmanBranch(
+ huffmanLeaf(2'u),
+ huffmanLeaf(3'u)))
+
+ test "equality":
+ check huffmanLeaf(12'u) == huffmanLeaf(12'u)
+ check huffmanLeaf(12'u) != huffmanLeaf(21'u)
+ check huffmanLeaf(12'u) != huffmanBranch(huffmanLeaf(12'u), huffmanLeaf(12'u))
+ check huffmanBranch(huffmanLeaf(12'u), huffmanLeaf(21'u)) == huffmanBranch(huffmanLeaf(12'u), huffmanLeaf(21'u))
+ check huffmanBranch(huffmanLeaf(12'u), huffmanLeaf(21'u)) != huffmanBranch(huffmanLeaf(12'u), huffmanLeaf(1'u))
+ check tree == tree
+
+ test "maxValue":
+ check tree.maxValue() == 3
+
+ test "deserialise":
+ let stream = newStringStream()
+ defer: stream.close()
+ let bitWriter = stream.bitWriter()
+ bitWriter.writeBits(valueLengthFieldBitLength, 2'u8)
+ bitWriter.writeBool(false) # root
+ bitWriter.writeBool(true) # 1 leaf
+ bitWriter.writeBits(2, 1'u)
+ bitWriter.writeBool(false) # right branch
+ bitWriter.writeBool(true) # 2 leaf
+ bitWriter.writeBits(2, 2'u)
+ bitWriter.writeBool(true) # 3 leaf
+ bitWriter.writeBits(2, 3'u)
+ bitWriter.flush()
+
+ stream.setPosition(0)
+ let bitReader = stream.bitReader()
+ check huffmantree.deserialise(bitReader, uint) == tree
+
+ test "serialise":
+ let stream = newStringStream()
+ defer: stream.close()
+ let bitWriter = stream.bitWriter()
+ tree.serialise(bitWriter)
+ bitWriter.flush()
+
+ stream.setPosition(0)
+ let bitReader = stream.bitReader()
+ check bitReader.readBits(valueLengthFieldBitLength, uint8) == 2
+ check bitReader.readBool() == false # root
+ check bitReader.readBool() == true # 1 leaf
+ check bitReader.readBits(2, uint8) == 1
+ check bitReader.readBool() == false # right branch
+ check bitReader.readBool() == true # 2 leaf
+ check bitReader.readBits(2, uint8) == 2
+ check bitReader.readBool() == true # 3 leaf
+ check bitReader.readBits(2, uint8) == 3
diff --git a/tests/huffman/thuffmantreebuilder.nim b/tests/huffman/thuffmantreebuilder.nim
new file mode 100644
index 0000000..1045f1d
--- /dev/null
+++ b/tests/huffman/thuffmantreebuilder.nim
@@ -0,0 +1,30 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, streams, sequtils, tables
+import huffman/huffmantree, huffman/huffmantreebuilder
+
+suite "huffmantreebuilder":
+ let
+ stats = newCountTable(concat(repeat(1'u, 3), repeat(2'u, 1), repeat(3'u, 2)))
+ tree = huffmanBranch(
+ huffmanLeaf(1'u),
+ huffmanBranch(
+ huffmanLeaf(2'u),
+ huffmanLeaf(3'u)))
+
+ test "buildHuffmanTree":
+ check buildHuffmanTree(stats) == tree
diff --git a/tests/lzss/tlzsschain.nim b/tests/lzss/tlzsschain.nim
new file mode 100644
index 0000000..92bee0f
--- /dev/null
+++ b/tests/lzss/tlzsschain.nim
@@ -0,0 +1,29 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest
+import lzss/lzssnode, lzss/lzsschain
+
+suite "lzsschain":
+ test "decode":
+ let chain = lzssChain([
+ lzssCharacter(0), lzssCharacter(1), lzssCharacter(2),
+ lzssCharacter(3), lzssCharacter(4), lzssCharacter(5),
+ lzssReference(4, 6), lzssCharacter(0), lzssCharacter(1),
+ lzssReference(3, 8), lzssCharacter(5),
+ lzssReference(3, 3), lzssCharacter(5)])
+ check chain.decode() == @[0'u8, 1, 2, 3, 4, 5, 0, 1, 2, 3, 0, 1, 4, 5, 0, 5, 5, 0, 5, 5]
+
\ No newline at end of file
diff --git a/tests/lzss/tlzssencoder.nim b/tests/lzss/tlzssencoder.nim
new file mode 100644
index 0000000..48477d7
--- /dev/null
+++ b/tests/lzss/tlzssencoder.nim
@@ -0,0 +1,59 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, sequtils
+import lzss/matchring, lzss/matchtable, lzss/lzssnode, lzss/lzssencoder
+
+suite "lzssencoder":
+ test "commonPrefixLength":
+ check commonPrefixLength([], [], 10) == 0
+ check commonPrefixLength([1'u8, 2], [1'u8, 2, 3], 10) == 2
+ check commonPrefixLength([1'u8, 2], [1'u8, 2, 3], 10) == 2
+ check commonPrefixLength([1'u8, 2, 3], [1'u8, 2, 4], 10) == 2
+ check commonPrefixLength([1'u8, 2, 3, 4], [1'u8, 2, 3, 4], 3) == 3
+
+ test "longestPrefix":
+ let buffer = [
+ 0'u8, 1, 2, 9,
+ 0, 1, 2, 3,
+ 0, 1, 2,
+ 0, 1, 2, 3, 4]
+ var candidatePos = [0, 4, 8]
+ var matchRing = initMatchRing()
+ for pos in candidatePos: matchRing.addMatch(pos)
+ let result = longestPrefix(matchRing, buffer.toOpenArray(0, 10), buffer.toOpenArray(11, buffer.len - 1))
+ check result.pos == 4
+ check result.length == 4
+
+ test "addGroups":
+ var matchTable = initMatchTable()
+ let buffer = toSeq(0'u8..10'u8)
+ matchTable.addGroups(buffer, 0, 1)
+ matchTable.addGroups(buffer, 2, 9)
+ check toSeq(matchTable.candidates([1'u8, 2, 3]).items).len == 0
+ check toSeq(matchTable.candidates([7'u8, 8, 9]).items).len == 0
+ check toSeq(matchTable.candidates([2'u8, 3, 4]).items) == [2]
+ check toSeq(matchTable.candidates([4'u8, 5, 6]).items) == [4]
+ check toSeq(matchTable.candidates([6'u8, 7, 8]).items) == [6]
+
+ test "lzssEncode":
+ let buffer = [0'u8, 1, 2, 3, 4, 5, 0, 1, 2, 3, 0, 1, 4, 5, 0, 5, 5, 0, 5, 5]
+ check lzssEncode(buffer) == [
+ lzssCharacter(0), lzssCharacter(1), lzssCharacter(2),
+ lzssCharacter(3), lzssCharacter(4), lzssCharacter(5),
+ lzssReference(4, 6), lzssCharacter(0), lzssCharacter(1),
+ lzssReference(3, 8), lzssCharacter(5),
+ lzssReference(3, 3), lzssCharacter(5)]
diff --git a/tests/lzss/tlzssnode.nim b/tests/lzss/tlzssnode.nim
new file mode 100644
index 0000000..7675fc0
--- /dev/null
+++ b/tests/lzss/tlzssnode.nim
@@ -0,0 +1,26 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest
+import lzss/lzssnode
+
+suite "lzssnode":
+ test "equality":
+ check lzssCharacter(1) == lzssCharacter(1)
+ check lzssCharacter(0) != lzssCharacter(1)
+ check lzssReference(0, 1) == lzssReference(0, 1)
+ check lzssReference(1, 0) != lzssReference(0, 1)
+ check lzssCharacter(0) != lzssReference(0, 1)
diff --git a/tests/lzss/tmatchring.nim b/tests/lzss/tmatchring.nim
new file mode 100644
index 0000000..ccf3856
--- /dev/null
+++ b/tests/lzss/tmatchring.nim
@@ -0,0 +1,35 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, sequtils, algorithm
+import lzss/matchring
+
+suite "matchring":
+ test "items (empty)":
+ var ring = initMatchRing()
+ check toSeq(ring.items).len == 0
+
+ test "addMatch, items (partial)":
+ var ring = initMatchRing()
+ let items = [0, 1, 2]
+ for i in items: ring.addMatch(i)
+ check toSeq(ring.items) == items.reversed()
+
+ test "addMatch, items (rolling)":
+ var ring = initMatchRing()
+ let items = toSeq(0..13)
+ for i in items: ring.addMatch(i)
+ check toSeq(ring.items) == items[^matchLimit...
+
+import unittest, sequtils
+import lzss/matchring, lzss/matchtable
+
+suite "matchtable":
+ test "addMatch":
+ var matchTable = initMatchTable()
+ matchTable.addMatch([0'u8, 1, 2], 42)
+ matchTable.addMatch([2'u8, 1, 0], 24)
+ check toSeq(matchTable.candidates([0'u8, 1, 2]).items) == [42]
+ check toSeq(matchTable.candidates([2'u8, 1, 0]).items) == [24]
+ matchTable.addMatch([0'u8, 1, 2], 1337)
+ check toSeq(matchTable.candidates([0'u8, 1, 2]).items) == [1337, 42]
+ check toSeq(matchTable.candidates([2'u8, 1, 0]).items) == [24]
diff --git a/tests/lzsshuffman/tlzsshuffmandecoder.nim b/tests/lzsshuffman/tlzsshuffmandecoder.nim
new file mode 100644
index 0000000..b8cd589
--- /dev/null
+++ b/tests/lzsshuffman/tlzsshuffmandecoder.nim
@@ -0,0 +1,65 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, streams
+import bitio/bitwriter, bitio/bitreader
+import lzss/lzssnode
+import huffman/huffmantree, huffman/huffmandecoder
+import lzsshuffman/lzsshuffmansymbol, lzsshuffman/lzsshuffmandecoder
+
+suite "lzsshuffmandecoder":
+ test "readChain (empty)":
+ let symbolTree = huffmanLeaf(endSymbol.uint16)
+ let positionTree = huffmanLeaf(0'u16)
+ let stream = newStringStream()
+ defer: stream.close()
+ stream.write(0'u8) # eof
+ stream.setPosition(0)
+ let bitReader = stream.bitReader()
+ let result = readChain(bitReader, symbolTree.decoder(), positionTree.decoder(), 32_000)
+ check result.len == 0
+
+ test "readChain (minimal)":
+ let symbolTree = huffmanBranch(
+ huffmanBranch(
+ huffmanLeaf(0'u16),
+ huffmanLeaf(1'u16)),
+ huffmanBranch(
+ huffmanLeaf(257'u16),
+ huffmanBranch(
+ huffmanLeaf(2'u16),
+ huffmanLeaf(256'u16))))
+ let positionTree = huffmanBranch(
+ huffmanLeaf(3'u16),
+ huffmanLeaf(4'u16))
+ let stream = newStringStream()
+ defer: stream.close()
+ let bitWriter = stream.bitWriter()
+ bitWriter.writeBits(2, 0b00'u8)
+ bitWriter.writeBits(2, 0b10'u8)
+ bitWriter.writeBits(3, 0b011'u8)
+ bitWriter.writeBits(2, 0b01'u8)
+ bitWriter.writeBits(1, 0b0'u8)
+ bitWriter.writeBits(2, 0b01'u8)
+ bitWriter.writeBits(1, 0b1'u8)
+ bitWriter.writeBits(3, 0b111'u8)
+ bitWriter.flush()
+ stream.setPosition(0)
+ let bitReader = stream.bitReader()
+ let result = readChain(bitReader, symbolTree.decoder(), positionTree.decoder(), 32_000)
+ check result == [
+ lzssCharacter(0), lzssCharacter(1), lzssCharacter(2),
+ lzssReference(3, 3), lzssReference(3, 4)]
diff --git a/tests/lzsshuffman/tlzsshuffmanencoder.nim b/tests/lzsshuffman/tlzsshuffmanencoder.nim
new file mode 100644
index 0000000..100b5f4
--- /dev/null
+++ b/tests/lzsshuffman/tlzsshuffmanencoder.nim
@@ -0,0 +1,66 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, streams
+import bitio/bitwriter, bitio/bitreader
+import lzss/lzssnode, lzss/lzsschain
+import huffman/huffmantree, huffman/huffmanencoder
+import lzsshuffman/lzsshuffmansymbol, lzsshuffman/lzsshuffmanencoder
+
+suite "lzsshuffmanencoder":
+ test "writeChain (empty)":
+ let chain = lzssChain(newSeq[LzssNode]())
+ let symbolTree = huffmanLeaf(endSymbol.uint16)
+ let positionTree = huffmanLeaf(0'u16)
+ let stream = newStringStream()
+ defer: stream.close()
+ let bitWriter = stream.bitWriter()
+ writeChain(chain, symbolTree.encoder(uint16), positionTree.encoder(uint16), bitWriter)
+ bitWriter.flush()
+ stream.setPosition(0)
+ check stream.atEnd()
+
+ test "writeChain (minimal)":
+ let chain = lzssChain([
+ lzssCharacter(0), lzssCharacter(1), lzssCharacter(2),
+ lzssReference(3, 3), lzssReference(3, 4)])
+ let symbolTree = huffmanBranch(
+ huffmanBranch(
+ huffmanLeaf(0'u16),
+ huffmanLeaf(1'u16)),
+ huffmanBranch(
+ huffmanLeaf(257'u16),
+ huffmanBranch(
+ huffmanLeaf(2'u16),
+ huffmanLeaf(256'u16))))
+ let positionTree = huffmanBranch(
+ huffmanLeaf(3'u16),
+ huffmanLeaf(4'u16))
+ let stream = newStringStream()
+ defer: stream.close()
+ let bitWriter = stream.bitWriter()
+ writeChain(chain, symbolTree.encoder(uint16), positionTree.encoder(uint16), bitWriter)
+ bitWriter.flush()
+ stream.setPosition(0)
+ let bitReader = stream.bitReader()
+ check bitReader.readBits(2, uint8) == 0b00'u8 # char 0
+ check bitReader.readBits(2, uint8) == 0b10'u8 # char 1
+ check bitReader.readBits(3, uint8) == 0b011'u8 # char 2
+ check bitReader.readBits(2, uint8) == 0b01'u8 # ref len 3
+ check bitReader.readBits(1, uint8) == 0b0'u8 # ref pos 3
+ check bitReader.readBits(2, uint8) == 0b01'u8 # ref len 3
+ check bitReader.readBits(1, uint8) == 0b1'u8 # ref pos 4
+ check bitReader.readBits(3, uint8) == 0b111'u8 # eof
diff --git a/tests/lzsshuffman/tlzsshuffmanstats.nim b/tests/lzsshuffman/tlzsshuffmanstats.nim
new file mode 100644
index 0000000..55eaf96
--- /dev/null
+++ b/tests/lzsshuffman/tlzsshuffmanstats.nim
@@ -0,0 +1,35 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest, tables, sequtils
+import lzss/lzssnode, lzss/lzsschain
+import lzsshuffman/lzsshuffmansymbol, lzsshuffman/lzsshuffmanstats
+
+suite "lzsshuffmanstats":
+ test "aggretateStats":
+ let chain = lzssChain([
+ lzssCharacter(0), lzssCharacter(1), lzssCharacter(2),
+ lzssCharacter(3), lzssCharacter(4), lzssCharacter(5),
+ lzssReference(4, 6), lzssCharacter(0), lzssCharacter(1),
+ lzssReference(3, 8), lzssCharacter(5),
+ lzssReference(3, 3), lzssCharacter(5)])
+ let (symbolTable, positionTable) = chain.aggregateStats()
+ check symbolTable == newCountTable(concat(
+ repeat(0'u16, 2), repeat(1'u16, 2), repeat(2'u16, 1), repeat(3'u16, 1), repeat(4'u16, 1), repeat(5'u16, 3),
+ repeat(endSymbol.uint16, 1),
+ repeat(257'u16, 2), repeat(258'u16, 1)))
+ check positionTable == newCountTable(concat(
+ repeat(3'u16, 1), repeat(6'u16, 1), repeat(8'u16, 1)))
diff --git a/tests/lzsshuffman/tlzsshuffmansymbol.nim b/tests/lzsshuffman/tlzsshuffmansymbol.nim
new file mode 100644
index 0000000..1e4653d
--- /dev/null
+++ b/tests/lzsshuffman/tlzsshuffmansymbol.nim
@@ -0,0 +1,37 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import unittest
+import lzss/lzssnode
+import lzsshuffman/lzsshuffmansymbol
+
+suite "lzsshuffmansymbol":
+ test "isEndMarker":
+ check 'a'.Symbol.isEndMarker() == false
+ check endSymbol.isEndMarker()
+
+ test "isCharacter":
+ check 'a'.Symbol.isCharacter()
+ check endSymbol.isCharacter() == false
+ check 300.Symbol.isCharacter() == false
+
+ test "unpackLzssReference":
+ check unpackLzssReference(257.Symbol, 10) == lzssReference(3, 10)
+ check unpackLzssReference(300.Symbol, 10) == lzssReference(46, 10)
+
+ test "shiftLzssLength":
+ check shiftLzssLength(3) == 257'u16
+ check shiftLzssLength(10) == 264'u16
diff --git a/tests/tbitio.nim b/tests/tbitio.nim
deleted file mode 100644
index 91b9cbf..0000000
--- a/tests/tbitio.nim
+++ /dev/null
@@ -1,176 +0,0 @@
-# gzip-like LZSS compressor
-# Copyright (C) 2018 Pacien TRAN-GIRARD
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import unittest, streams, sugar, sequtils
-import bitio/integers, bitio/bitreader, bitio/bitwriter
-
-suite "integers":
- test "Round-up integer division":
- check 42 /^ 2 == 21
- check 43 /^ 2 == 22
-
- test "truncateToUint8":
- check truncateToUint8(0xFA'u8) == 0xFA'u8
- check truncateToUint8(0x00FA'u16) == 0xFA'u8
- check truncateToUint8(0xFFFA'u16) == 0xFA'u8
-
- test "bitLength":
- check bitLength(0b1_1111) == 5
- check bitLength(0b1000_0000) == 8
-
- test "leastSignificantBits":
- check leastSignificantBits(0xFF'u8, 3) == 0b0000_0111'u8
- check leastSignificantBits(0b0001_0101'u8, 3) == 0b0000_0101'u8
- check leastSignificantBits(0xFF'u8, 10) == 0xFF'u8
- check leastSignificantBits(0xFFFF'u16, 16) == 0xFFFF'u16
- check leastSignificantBits(0xFFFF'u16, 8) == 0x00FF'u16
-
- test "chunks iterator":
- check toSeq(chunks(70, uint32)) == @[(0, 32), (1, 32), (2, 6)]
- check toSeq(chunks(32, uint16)) == @[(0, 16), (1, 16)]
-
-suite "bitreader":
- test "readBool":
- let stream = newStringStream()
- defer: stream.close()
- stream.write(0b1001_1111'u8)
- stream.write(0b0110_0000'u8)
- stream.setPosition(0)
-
- let bitReader = stream.bitReader()
- check lc[bitReader.readBool() | (_ <- 0..<16), bool] == @[
- true, true, true, true, true, false, false, true,
- false, false, false, false, false, true, true, false]
-
- expect IOError: discard bitReader.readBool()
- check bitReader.atEnd()
-
- test "readBits":
- let stream = newStringStream()
- defer: stream.close()
- stream.write(0xF00F'u16)
- stream.write(0x0FFF'u16)
- stream.setPosition(0)
-
- let bitReader = stream.bitReader()
- check bitReader.readBits(8, uint8) == 0x0F'u8
- check bitReader.readBits(16, uint16) == 0xFFF0'u16
- check bitReader.readBits(8, uint8) == 0x0F'u8
-
- expect RangeError: discard bitReader.readBits(9, uint8)
- expect IOError: discard bitReader.readBits(16, uint16)
- check bitReader.atEnd()
-
- test "readBits (look-ahead overflow)":
- let stream = newStringStream()
- defer: stream.close()
- stream.write(0xAB'u8)
- stream.setPosition(0)
-
- let bitReader = stream.bitReader()
- check bitReader.readBits(4, uint16) == 0x000B'u16
- check bitReader.readBits(4, uint16) == 0x000A'u16
- check bitReader.atEnd()
-
- test "readBits (from buffer composition)":
- let stream = newStringStream()
- defer: stream.close()
- stream.write(0xABCD'u16)
- stream.setPosition(0)
-
- let bitReader = stream.bitReader()
- check bitReader.readBits(4, uint16) == 0x000D'u16
- check bitReader.readBits(8, uint16) == 0x00BC'u16
- check bitReader.readBits(4, uint16) == 0x000A'u16
- check bitReader.atEnd()
-
- test "readSeq":
- let stream = newStringStream()
- defer: stream.close()
- stream.write(0x0F00_F0FF_F0F0_F0F0'u64)
- stream.setPosition(0)
-
- let bitReader = stream.bitReader()
- check bitReader.readSeq(32, uint16) == (32, @[0xF0F0'u16, 0xF0F0])
- check bitReader.readSeq(40, uint8) == (32, @[0xFF'u8, 0xF0, 0x00, 0x0F])
- check bitReader.atEnd()
-
-suite "bitwriter":
- test "flush":
- let stream = newStringStream()
- defer: stream.close()
- let bitWriter = stream.bitWriter()
-
- bitWriter.writeBool(true)
- stream.setPosition(0)
- expect IOError: discard stream.peekUint8()
-
- bitWriter.flush()
- stream.setPosition(0)
- check stream.readUint8() == 0x01'u8
- check stream.atEnd()
-
- bitWriter.flush()
- check stream.atEnd()
-
- test "writeBool":
- let stream = newStringStream()
- defer: stream.close()
-
- let bitWriter = stream.bitWriter()
- let booleanValues = @[
- true, true, true, true, true, false, false, true,
- false, false, false, false, false, true, true, false,
- true, true, false, true]
- for b in booleanValues: bitWriter.writeBool(b)
- bitWriter.flush()
-
- stream.setPosition(0)
- check stream.readUint8() == 0b1001_1111'u8
- check stream.readUint8() == 0b0110_0000'u8
- check stream.readUint8() == 0b0000_1011'u8
- expect IOError: discard stream.readUint8()
- check stream.atEnd()
-
- test "writeBits":
- let stream = newStringStream()
- defer: stream.close()
-
- let bitWriter = stream.bitWriter()
- bitWriter.writeBits(4, 0xF00F'u16)
- bitWriter.writeBits(16, 0xF00F'u16)
- bitWriter.writeBits(16, 0xFFFF'u16)
- bitWriter.flush()
-
- stream.setPosition(0)
- check stream.readUint16() == 0x00FF'u16
- check stream.readUint16() == 0xFFFF'u16
- check stream.readUint8() == 0x0F'u8
- expect IOError: discard stream.readUint8()
- check stream.atEnd()
-
- test "writeSeq":
- let stream = newStringStream()
- defer: stream.close()
-
- let bitWriter = stream.bitWriter()
- bitWriter.writeSeq(32, @[0xF0F0'u16, 0xF0F0])
- bitWriter.writeSeq(28, @[0xFF'u8, 0xF0, 0x00, 0xFF])
- bitWriter.flush()
-
- stream.setPosition(0)
- check stream.readUint64() == 0x0F00_F0FF_F0F0_F0F0'u64
- check stream.atEnd()
diff --git a/tests/tblocks.nim b/tests/tblocks.nim
deleted file mode 100644
index 540317d..0000000
--- a/tests/tblocks.nim
+++ /dev/null
@@ -1,107 +0,0 @@
-# gzip-like LZSS compressor
-# Copyright (C) 2018 Pacien TRAN-GIRARD
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import unittest, streams
-import bitio/bitreader, bitio/bitwriter, blocks/rawblock, blocks/streamblock
-
-suite "rawblock":
- test "serialise":
- let rawStream = newStringStream()
- defer: rawStream.close()
- rawStream.write(0xFEDC_BA98_7654_3210'u64)
- rawStream.setPosition(0)
- let rawBitReader = rawStream.bitReader()
- let rawBlock = rawblock.readRaw(rawBitReader)
-
- let outputStream = newStringStream()
- defer: outputStream.close()
- let outputBitWriter = outputStream.bitWriter()
- rawBlock.writeSerialisedTo(outputBitWriter)
- outputBitWriter.flush()
-
- outputStream.setPosition(0)
- check outputStream.readUint16() == 64
- check outputStream.readUint64() == 0xFEDC_BA98_7654_3210'u64
- check outputStream.atEnd()
-
- test "deserialise":
- let serialisedStream = newStringStream()
- defer: serialisedStream.close()
- serialisedStream.write(60'u16)
- serialisedStream.write(0xFEDC_BA98_7654_3210'u64)
- serialisedStream.setPosition(0)
- let serialisedBitReader = serialisedStream.bitReader()
- let rawBlock = rawBlock.readSerialised(serialisedBitReader)
-
- let outputStream = newStringStream()
- defer: outputStream.close()
- let outputBitWriter = outputStream.bitWriter()
- rawBlock.writeRawTo(outputBitWriter)
- outputBitWriter.flush()
-
- outputStream.setPosition(0)
- check outputStream.readUint64 == 0x0EDC_BA98_7654_3210'u64
- check outputStream.atEnd()
-
-suite "streamblock":
- test "serialise":
- let rawStream = newStringStream()
- defer: rawStream.close()
- rawStream.write(0xFEDC_BA98_7654_3210'u64)
- rawStream.setPosition(0)
- let rawBitReader = rawStream.bitReader()
- let streamBlock = readRaw(rawBitReader, uncompressed)
- check streamBlock.isLast()
-
- let outputStream = newStringStream()
- defer: outputStream.close()
- let outputBitWriter = outputStream.bitWriter()
- streamBlock.writeSerialisedTo(outputBitWriter)
- outputBitWriter.flush()
-
- outputStream.setPosition(0)
- let produceReader = outputStream.bitReader()
- check produceReader.readBool() == true # last block flag
- check produceReader.readBits(2, uint8) == 0x00'u8 # block kind
- check produceReader.readBits(16, uint16) == 64 # raw block length
- check produceReader.readSeq(64, uint8) == (64, @[0x10'u8, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE]) # raw block content
- discard produceReader.readBits(8 - 2 - 1, uint8)
- check produceReader.atEnd()
-
- test "deserialise":
- let serialisedStream = newStringStream()
- defer: serialisedStream.close()
- let serialisedBitWriter = serialisedStream.bitWriter()
- serialisedBitWriter.writeBool(true)
- serialisedBitWriter.writeBits(2, 0x00'u8)
- serialisedBitWriter.writeBits(16, 64'u16)
- serialisedBitWriter.writeBits(64, 0xFEDC_BA98_7654_3210'u64)
- serialisedBitWriter.flush()
-
- serialisedStream.setPosition(0)
- let serialisedBitReader = serialisedStream.bitReader()
- let streamBlock = streamblock.readSerialised(serialisedBitReader)
-
- let outputStream = newStringStream()
- defer: outputStream.close()
- let outputBitWriter = outputStream.bitWriter()
- check streamBlock.isLast()
- streamBlock.writeRawTo(outputBitWriter)
- outputBitWriter.flush()
-
- outputStream.setPosition(0)
- check outputStream.readUint64 == 0xFEDC_BA98_7654_3210'u64
- check outputStream.atEnd()
diff --git a/tests/tests.nim b/tests/tests.nim
new file mode 100644
index 0000000..23b6e1c
--- /dev/null
+++ b/tests/tests.nim
@@ -0,0 +1,42 @@
+# gzip-like LZSS compressor
+# Copyright (C) 2018 Pacien TRAN-GIRARD
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import
+ bitio/tintegers,
+ bitio/tbitreader,
+ bitio/tbitwriter,
+
+ huffman/thuffmantree,
+ huffman/thuffmantreebuilder,
+ huffman/thuffmanencoder,
+ huffman/thuffmandecoder,
+
+ lzss/tmatchring,
+ lzss/tmatchtable,
+ lzss/tlzssnode,
+ lzss/tlzsschain,
+ lzss/tlzssencoder,
+
+ lzsshuffman/tlzsshuffmansymbol,
+ lzsshuffman/tlzsshuffmanstats,
+ lzsshuffman/tlzsshuffmanencoder,
+ lzsshuffman/tlzsshuffmandecoder,
+
+ blocks/trawblock,
+ # TODO: add lzssblock test
+ blocks/streamblock,
+
+ gziplike/tgziplike
diff --git a/tests/tgziplike.nim b/tests/tgziplike.nim
deleted file mode 100644
index 836e4be..0000000
--- a/tests/tgziplike.nim
+++ /dev/null
@@ -1,40 +0,0 @@
-# gzip-like LZSS compressor
-# Copyright (C) 2018 Pacien TRAN-GIRARD
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import unittest, os, ospaths, osproc, times
-import gziplike
-
-suite "main":
- const tempDir = "tmp"
-
- proc testIdentity(input: string, intermediate = tempDir / "compressed", final = tempDir / "decompressed"): bool =
- let compressionStartTime = getTime()
- compress.transform(input, intermediate)
- echo("compression done in ", getTime() - compressionStartTime)
- echo("compression ratio: ", (intermediate.getFileSize() * 100) div input.getFileSize(), "%")
- let decompressionStartTime = getTime()
- decompress.transform(intermediate, final)
- echo("decompression done in ", getTime() - decompressionStartTime)
- startProcess("cmp", args=[input, final], options={poUsePath}).waitForExit() == 0
-
- setup: createDir(tempDir)
- teardown: removeDir(tempDir)
-
- test "identity (text)":
- check testIdentity("license.md")
-
- test "identity (binary)":
- check testIdentity("tests" / "tgziplike")
diff --git a/tests/thuffman.nim b/tests/thuffman.nim
deleted file mode 100644
index db209f4..0000000
--- a/tests/thuffman.nim
+++ /dev/null
@@ -1,119 +0,0 @@
-# gzip-like LZSS compressor
-# Copyright (C) 2018 Pacien TRAN-GIRARD
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import unittest, streams, sequtils, tables, heapqueue
-import bitio/bitreader, bitio/bitwriter
-import huffman/huffmantree, huffman/huffmantreebuilder, huffman/huffmanencoder, huffman/huffmandecoder
-
-let
- stats = newCountTable(concat(repeat(1'u, 3), repeat(2'u, 1), repeat(3'u, 2)))
- tree = huffmanBranch(
- huffmanLeaf(1'u),
- huffmanBranch(
- huffmanLeaf(2'u),
- huffmanLeaf(3'u)))
-
-suite "huffmantree":
- test "equality":
- check huffmanLeaf(12'u) == huffmanLeaf(12'u)
- check huffmanLeaf(12'u) != huffmanLeaf(21'u)
- check huffmanLeaf(12'u) != huffmanBranch(huffmanLeaf(12'u), huffmanLeaf(12'u))
- check huffmanBranch(huffmanLeaf(12'u), huffmanLeaf(21'u)) == huffmanBranch(huffmanLeaf(12'u), huffmanLeaf(21'u))
- check huffmanBranch(huffmanLeaf(12'u), huffmanLeaf(21'u)) != huffmanBranch(huffmanLeaf(12'u), huffmanLeaf(1'u))
- check tree == tree
-
- test "maxValue":
- check tree.maxValue() == 3
-
- test "deserialise":
- let stream = newStringStream()
- defer: stream.close()
- let bitWriter = stream.bitWriter()
- bitWriter.writeBits(valueLengthFieldBitLength, 2'u8)
- bitWriter.writeBool(false) # root
- bitWriter.writeBool(true) # 1 leaf
- bitWriter.writeBits(2, 1'u)
- bitWriter.writeBool(false) # right branch
- bitWriter.writeBool(true) # 2 leaf
- bitWriter.writeBits(2, 2'u)
- bitWriter.writeBool(true) # 3 leaf
- bitWriter.writeBits(2, 3'u)
- bitWriter.flush()
-
- stream.setPosition(0)
- let bitReader = stream.bitReader()
- check huffmantree.deserialise(bitReader, uint) == tree
-
- test "serialise":
- let stream = newStringStream()
- defer: stream.close()
- let bitWriter = stream.bitWriter()
- tree.serialise(bitWriter)
- bitWriter.flush()
-
- stream.setPosition(0)
- let bitReader = stream.bitReader()
- check bitReader.readBits(valueLengthFieldBitLength, uint8) == 2
- check bitReader.readBool() == false # root
- check bitReader.readBool() == true # 1 leaf
- check bitReader.readBits(2, uint8) == 1
- check bitReader.readBool() == false # right branch
- check bitReader.readBool() == true # 2 leaf
- check bitReader.readBits(2, uint8) == 2
- check bitReader.readBool() == true # 3 leaf
- check bitReader.readBits(2, uint8) == 3
-
-suite "huffmantreebuilder":
- test "buildHuffmanTree":
- check buildHuffmanTree(stats) == tree
-
-suite "huffencoder":
- let tree = huffmanBranch(
- huffmanLeaf(1'u),
- huffmanBranch(
- huffmanLeaf(2'u),
- huffmanLeaf(3'u)))
-
- test "buildCodebook":
- let codebook = buildCodebook(tree, uint)
- check codebook.len == 3
- check codebook[1'u] == (1, 0b0'u)
- check codebook[2'u] == (2, 0b01'u)
- check codebook[3'u] == (2, 0b11'u)
-
- test "encode":
- let encoder = tree.encoder(uint)
- check encoder.encode(1'u) == (1, 0b0'u)
- check encoder.encode(2'u) == (2, 0b01'u)
- check encoder.encode(3'u) == (2, 0b11'u)
-
-suite "huffdecoder":
- test "decode":
- let stream = newStringStream()
- defer: stream.close()
- let bitWriter = stream.bitWriter()
- bitWriter.writeBool(true) # 2
- bitWriter.writeBool(false)
- bitWriter.writeBool(false) # 1
- bitWriter.writeBool(true) # 3
- bitWriter.writeBool(true)
- bitWriter.flush()
- stream.setPosition(0)
- let bitReader = stream.bitReader()
- let decoder = tree.decoder()
- check decoder.decode(bitReader) == 2'u
- check decoder.decode(bitReader) == 1'u
- check decoder.decode(bitReader) == 3'u
diff --git a/tests/tlzss.nim b/tests/tlzss.nim
deleted file mode 100644
index 39a89c6..0000000
--- a/tests/tlzss.nim
+++ /dev/null
@@ -1,105 +0,0 @@
-# gzip-like LZSS compressor
-# Copyright (C) 2018 Pacien TRAN-GIRARD
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-import unittest, sequtils, tables, lists, algorithm
-import lzss/matchring, lzss/matchtable, lzss/lzssnode, lzss/lzsschain, lzss/lzssencoder
-
-suite "matchring":
- test "items (empty)":
- var ring = initMatchRing()
- check toSeq(ring.items).len == 0
-
- test "addMatch, items (partial)":
- var ring = initMatchRing()
- let items = [0, 1, 2]
- for i in items: ring.addMatch(i)
- check toSeq(ring.items) == items.reversed()
-
- test "addMatch, items (rolling)":
- var ring = initMatchRing()
- let items = toSeq(0..13)
- for i in items: ring.addMatch(i)
- check toSeq(ring.items) == items[^matchLimit..