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 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..