OXYGENHUB
◆ main openmsx / src / unittest / CRC16_test.cc
3.4 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "catch.hpp"
2
#include "CRC16.hh"
3
4
#include "narrow.hh"
5
#include "xrange.hh"
6
7
#include <array>
8
#include <bit>
9
10
using namespace openmsx;
11
12
TEST_CASE("CRC16")
13
{
14
	CRC16 crc;
15
	REQUIRE(crc.getValue() == 0xFFFF);
16
17
	// Test a simple sequence
18
	SECTION("'3 x A1' in a loop") {
19
		repeat(3, [&] { crc.update(0xA1); });
20
		CHECK(crc.getValue() == 0xCDB4);
21
	}
22
	SECTION("'3 x A1' in one chunk") {
23
		static constexpr std::array<uint8_t, 3> buf = { 0xA1, 0xA1, 0xA1 };
24
		crc.update(buf);
25
		CHECK(crc.getValue() == 0xCDB4);
26
	}
27
	SECTION("'3 x A1' via init") {
28
		crc.init({0xA1, 0xA1, 0xA1});
29
		CHECK(crc.getValue() == 0xCDB4);
30
	}
31
32
	// Internally the block-update method works on chunks of 8 bytes,
33
	// so also try a few bigger examples
34
	//   not (an integer) multiple of 8
35
	SECTION("'123456789' in a loop") {
36
		for (char c : {'1', '2', '3', '4', '5', '6', '7', '8', '9'}) crc.update(c);
37
		CHECK(crc.getValue() == 0x29B1);
38
	}
39
	SECTION("'123456789' in one chunk") {
40
		static constexpr const char* const digits = "123456789";
41
		crc.update(std::span{std::bit_cast<const uint8_t*>(digits), 9});
42
		CHECK(crc.getValue() == 0x29B1);
43
	}
44
	// same as disk sector size
45
	SECTION("512 bytes") {
46
		std::array<uint8_t, 512> buf;
47
		for (auto i : xrange(512)) buf[i] = narrow_cast<uint8_t>(i & 255);
48
		SECTION("in a loop") {
49
			for (char c : buf) crc.update(c);
50
			CHECK(crc.getValue() == 0x56EE);
51
		}
52
		SECTION("in one chunk") {
53
			crc.update(buf);
54
			CHECK(crc.getValue() == 0x56EE);
55
		}
56
	}
57
58
	// Tests for init<..>()
59
	// It's possible to pass up-to 4 parameters. Verify that this gives
60
	// the same result as the other 2 CRC calculation methods.
61
	SECTION("'11' in a loop") {
62
		for (uint8_t c : {uint8_t(0x11)}) crc.update(c);
63
		CHECK(crc.getValue() == 0xE3E0);
64
	}
65
	SECTION("'11' in one chunk") {
66
		static constexpr std::array<uint8_t, 1> buf = {0x11};
67
		crc.update(buf);
68
		CHECK(crc.getValue() == 0xE3E0);
69
	}
70
	SECTION("'11' via init") {
71
		crc.init({0x11});
72
		CHECK(crc.getValue() == 0xE3E0);
73
	}
74
75
	SECTION("'11 22' in a loop") {
76
		for (uint8_t c : {uint8_t(0x11), uint8_t(0x22)}) crc.update(c);
77
		CHECK(crc.getValue() == 0x296D);
78
	}
79
	SECTION("'11 22' in one chunk") {
80
		static constexpr std::array<uint8_t, 2> buf = {0x11, 0x22};
81
		crc.update(buf);
82
		CHECK(crc.getValue() == 0x296D);
83
	}
84
	SECTION("'11 22' via init") {
85
		crc.init({0x11, 0x22});
86
		CHECK(crc.getValue() == 0x296D);
87
	}
88
89
	SECTION("'11 22 33' in a loop") {
90
		for (uint8_t c : {uint8_t(0x11), uint8_t(0x22), uint8_t(0x33)}) crc.update(c);
91
		CHECK(crc.getValue() == 0xDE7B);
92
	}
93
	SECTION("'11 22 33' in one chunk") {
94
		static constexpr std::array<uint8_t, 3> buf = {0x11, 0x22, 0x33};
95
		crc.update(buf);
96
		CHECK(crc.getValue() == 0xDE7B);
97
	}
98
	SECTION("'11 22 33' via init") {
99
		crc.init({0x11, 0x22, 0x33});
100
		CHECK(crc.getValue() == 0xDE7B);
101
	}
102
103
	SECTION("'11 22 33 44' in a loop") {
104
		for (uint8_t c : {uint8_t(0x11), uint8_t(0x22), uint8_t(0x33), uint8_t(0x44)}) crc.update(c);
105
		CHECK(crc.getValue() == 0x59F3);
106
	}
107
	SECTION("'11 22 33 44' in one chunk") {
108
		static constexpr std::array<uint8_t, 4> buf = {0x11, 0x22, 0x33, 0x44};
109
		crc.update(buf);
110
		CHECK(crc.getValue() == 0x59F3);
111
	}
112
	SECTION("'11 22 33 44' via init") {
113
		crc.init({0x11, 0x22, 0x33, 0x44});
114
		CHECK(crc.getValue() == 0x59F3);
115
	}
116
}
117
118
119
#if 0
120
121
// Functions to inspect the quality of the generated code
122
123
uint16_t test_init()
124
{
125
	// I verified that gcc is capable of optimizing this to 'return 0xcdb4'.
126
	CRC16 crc;
127
	crc.init({0xA1, 0xA1, 0xA1});
128
	return crc.getValue();
129
}
130
131
#endif