Livt packages

Livt.Utils

Version 1.1.1

Reusable Livt utility components, including configurable CRC helpers and CRC32.

Published files (8)

tests/hashing/Crc32Test.lvt

namespace Livt.Utils.Tests.Hashing

using Livt.Utils.Hashing

/**
 * Tests for Crc32 (IEEE 802.3 / zlib, reflected polynomial 0xEDB88320).
 */
@Test
component Crc32Test
{
	// Shared fixture instances, signals, and observation state.
	crc: Crc32

	/**
	 * Initialises the component under test.
	 */
	new()
	{
		crc = new Crc32()
	}

	/**
	 * CRC32("") = 0x00000000
	 * Reset followed by ProcessFinalBlock(zeros, 0).
	 */
	@Test
	fn TestEmptyInput()
	{
		crc.Reset()

		var blk: byte[16] = [
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
		crc.ProcessFinalBlock(blk, 0)

		assert crc.GetByte(0) == 0x00
		assert crc.GetByte(1) == 0x00
		assert crc.GetByte(2) == 0x00
		assert crc.GetByte(3) == 0x00
	}

	/**
	 * CRC32("123456789") = 0xCBF43926
	 * Standard ISO 3309 / ITU-T V.42 check value.
	 * Little-endian bytes: 0x26, 0x39, 0xF4, 0xCB
	 */
	@Test
	fn TestKnownVector()
	{
		crc.Reset()

		// "123456789" = 0x31..0x39, zero-padded to 16 bytes
		var blk: byte[16] = [
			0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
			0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
		crc.ProcessFinalBlock(blk, 9)

		var result: byte[4] = crc.GetCrc()
		assert result[0] == 0x26
		assert result[1] == 0x39
		assert result[2] == 0xF4
		assert result[3] == 0xCB
	}

	/**
	 * CRC32("123456789012345678") = 0xB78D9278
	 * First 16 bytes via ProcessBlock, last 2 via ProcessFinalBlock.
	 * Little-endian bytes: 0x78, 0x92, 0x8D, 0xB7
	 */
	@Test
	fn TestMultiBlock()
	{
		crc.Reset()

		// "1234567890123456" (16 bytes)
		var blk1: byte[16] = [
			0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
			0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36]
		crc.ProcessBlock(blk1)

		// "78" (2 bytes), zero-padded to 16
		var blk2: byte[16] = [
			0x37, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
		crc.ProcessFinalBlock(blk2, 2)

		assert crc.GetByte(0) == 0x78
		assert crc.GetByte(1) == 0x92
		assert crc.GetByte(2) == 0x8D
		assert crc.GetByte(3) == 0xB7
	}

	/**
	 * Computing the same input twice with Reset between must give the same
	 * result, confirming that Reset fully restores the initial state.
	 */
	@Test
	fn TestReset()
	{
		// First computation
		crc.Reset()
		var blk: byte[16] = [
			0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
			0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
		crc.ProcessFinalBlock(blk, 9)
		var r0: byte = crc.GetByte(0)
		var r1: byte = crc.GetByte(1)
		var r2: byte = crc.GetByte(2)
		var r3: byte = crc.GetByte(3)

		// Second computation — must produce identical result
		crc.Reset()
		var blk2: byte[16] = [
			0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
			0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
		crc.ProcessFinalBlock(blk2, 9)

		assert crc.GetByte(0) == r0
		assert crc.GetByte(1) == r1
		assert crc.GetByte(2) == r2
		assert crc.GetByte(3) == r3
	}

	/**
	 * CRC32(0x00) = 0xD202EF8D
	 * Boundary: single zero byte — exercises table entry at index 0xFF.
	 * Little-endian bytes: 0x8D, 0xEF, 0x02, 0xD2
	 */
	@Test
	fn TestSingleByteZero()
	{
		crc.Reset()

		var blk: byte[16] = [
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
		crc.ProcessFinalBlock(blk, 1)

		assert crc.GetByte(0) == 0x8D
		assert crc.GetByte(1) == 0xEF
		assert crc.GetByte(2) == 0x02
		assert crc.GetByte(3) == 0xD2
	}

	/**
	 * CRC32(0xFF) = 0xFF000000
	 * Boundary: single 0xFF byte — exercises table entry at index 0x00.
	 * Little-endian bytes: 0x00, 0x00, 0x00, 0xFF
	 */
	@Test
	fn TestSingleByteFF()
	{
		crc.Reset()

		var blk: byte[16] = [
			0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
		crc.ProcessFinalBlock(blk, 1)

		assert crc.GetByte(0) == 0x00
		assert crc.GetByte(1) == 0x00
		assert crc.GetByte(2) == 0x00
		assert crc.GetByte(3) == 0xFF
	}

	/**
	 * CRC32("The quick brown fox jumps over the lazy dog") = 0x414FA339
	 * 43-byte input split across two ProcessBlock calls and one ProcessFinalBlock.
	 * Little-endian bytes: 0x39, 0xA3, 0x4F, 0x41
	 */
	@Test
	fn TestQuickBrownFox()
	{
		crc.Reset()

		// "The quick brown " (bytes 0-15)
		var blk1: byte[16] = [
			0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63,
			0x6B, 0x20, 0x62, 0x72, 0x6F, 0x77, 0x6E, 0x20]
		crc.ProcessBlock(blk1)

		// "fox jumps over t" (bytes 16-31)
		var blk2: byte[16] = [
			0x66, 0x6F, 0x78, 0x20, 0x6A, 0x75, 0x6D, 0x70,
			0x73, 0x20, 0x6F, 0x76, 0x65, 0x72, 0x20, 0x74]
		crc.ProcessBlock(blk2)

		// "he lazy dog" (bytes 32-42, len=11), zero-padded to 16
		var blk3: byte[16] = [
			0x68, 0x65, 0x20, 0x6C, 0x61, 0x7A, 0x79, 0x20,
			0x64, 0x6F, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00]
		crc.ProcessFinalBlock(blk3, 11)

		assert crc.GetByte(0) == 0x39
		assert crc.GetByte(1) == 0xA3
		assert crc.GetByte(2) == 0x4F
		assert crc.GetByte(3) == 0x41
	}
}