1 | // Boost CRC unit test program file ----------------------------------------// |
2 | |
3 | // Copyright 2011 Daryle Walker. |
4 | // Distributed under the Boost Software License, Version 1.0. (See the |
5 | // accompanying file LICENSE_1_0.txt or a copy at |
6 | // <http://www.boost.org/LICENSE_1_0.txt>.) |
7 | |
8 | // See <http://www.boost.org/libs/crc/> for the library's home page. |
9 | |
10 | #include <boost/core/lightweight_test.hpp> |
11 | #include <boost/crc.hpp> // for boost::crc_basic,crc_optimal,augmented_crc,crc |
12 | |
13 | #include <boost/cstdint.hpp> // for boost::uint16_t, uint32_t, uintmax_t |
14 | #include <boost/predef/other/endian.h> |
15 | #include <boost/integer.hpp> // for boost::uint_t |
16 | #include <boost/typeof/typeof.hpp> // for BOOST_AUTO |
17 | #include <boost/random/linear_congruential.hpp> // for boost::minstd_rand |
18 | |
19 | #include <algorithm> // for std::generate_n, for_each |
20 | #include <climits> // for CHAR_BIT |
21 | #include <cstddef> // for std::size_t |
22 | |
23 | // Sanity check |
24 | #if CHAR_BIT != 8 |
25 | #error The expected results assume octet-sized bytes. |
26 | #endif |
27 | |
28 | // Control tests at compile-time |
29 | #ifndef CONTROL_SUB_BYTE_MISMATCHED_REFLECTION_TEST |
30 | #define CONTROL_SUB_BYTE_MISMATCHED_REFLECTION_TEST 1 |
31 | #endif |
32 | |
33 | |
34 | // Common definitions -------------------------------------------------------// |
35 | |
36 | namespace { |
37 | |
38 | // Many CRC configurations use the string "123456789" in ASCII as test data. |
39 | unsigned char const std_data[] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, |
40 | 0x38, 0x39 }; |
41 | std::size_t const std_data_len = sizeof( std_data ) / sizeof( std_data[0] ); |
42 | |
43 | // Checksums of the standard test data for common configurations |
44 | boost::uint16_t const std_crc_ccitt_false_result = 0x29B1u; |
45 | boost::uint16_t const std_crc_ccitt_true_result = 0x2189u; |
46 | boost::uint16_t const std_crc_xmodem_result = 0x31C3u; |
47 | boost::uint16_t const std_crc_16_result = 0xBB3Du; |
48 | boost::uint32_t const std_crc_32_result = 0xCBF43926ul; |
49 | |
50 | // Conversion functions between native- and big-endian representations |
51 | #if BOOST_ENDIAN_BIG_BYTE |
52 | boost::uint32_t native_to_big( boost::uint32_t x ) { return x; } |
53 | boost::uint32_t big_to_native( boost::uint32_t x ) { return x; } |
54 | #else |
55 | union endian_convert |
56 | { |
57 | boost::uint32_t w; |
58 | unsigned char p[ 4 ]; |
59 | }; |
60 | |
61 | boost::uint32_t native_to_big( boost::uint32_t x ) |
62 | { |
63 | endian_convert e; |
64 | |
65 | e.p[ 0 ] = x >> 24; |
66 | e.p[ 1 ] = x >> 16; |
67 | e.p[ 2 ] = x >> 8; |
68 | e.p[ 3 ] = x; |
69 | return e.w; |
70 | } |
71 | |
72 | boost::uint32_t big_to_native( boost::uint32_t x ) |
73 | { |
74 | endian_convert e; |
75 | |
76 | e.w = x; |
77 | x = e.p[ 0 ]; |
78 | x <<= 8; |
79 | x |= e.p[ 1 ]; |
80 | x <<= 8; |
81 | x |= e.p[ 2 ]; |
82 | x <<= 8; |
83 | x |= e.p[ 3 ]; |
84 | return x; |
85 | } |
86 | #endif |
87 | |
88 | // Define CRC parameters inside traits classes. Probably will use this in a |
89 | // future version of the CRC libray! |
90 | template < std::size_t Bits > |
91 | class my_crc_rt_traits |
92 | { |
93 | public: |
94 | typedef boost::integral_constant<std::size_t, Bits> register_length_c; |
95 | typedef typename boost::uint_t<Bits>::fast register_type; |
96 | typedef boost::crc_basic<Bits> computer_type; |
97 | |
98 | register_type divisor_polynominal; |
99 | register_type initial_remainder; |
100 | bool reflect_input_byte; |
101 | bool reflect_output_remainder; |
102 | register_type final_xor_mask; |
103 | |
104 | computer_type make_crc_basic() const |
105 | { return computer_type(divisor_polynominal, initial_remainder, |
106 | final_xor_mask, reflect_input_byte, reflect_output_remainder); } |
107 | }; |
108 | |
109 | template < std::size_t Bits, boost::uintmax_t DivisorPolynominal, |
110 | boost::uintmax_t InitialRemainder, bool ReflectInputBytes, |
111 | bool ReflectOutputRemainder, boost::uintmax_t FinalXorMask > |
112 | class my_crc_ct_traits |
113 | { |
114 | public: |
115 | typedef my_crc_rt_traits<Bits> rt_adaptor_type; |
116 | typedef typename rt_adaptor_type::register_type register_type; |
117 | typedef boost::crc_optimal<Bits, DivisorPolynominal, InitialRemainder, |
118 | FinalXorMask, ReflectInputBytes, ReflectOutputRemainder> computer_type; |
119 | |
120 | typedef boost::integral_constant<std::size_t, Bits> register_length_c; |
121 | typedef boost::integral_constant<register_type, DivisorPolynominal> |
122 | divisor_polynominal_c; |
123 | typedef boost::integral_constant<register_type, InitialRemainder> |
124 | initial_remainder_c; |
125 | typedef boost::integral_constant<bool, ReflectInputBytes> reflect_input_byte_c; |
126 | typedef boost::integral_constant<bool, ReflectOutputRemainder> |
127 | reflect_output_remainder_c; |
128 | typedef boost::integral_constant<register_type, FinalXorMask> |
129 | final_xor_mask_c; |
130 | |
131 | operator rt_adaptor_type() const |
132 | { |
133 | rt_adaptor_type const result = { divisor_polynominal_c::value, |
134 | initial_remainder_c::value, reflect_input_byte_c::value, |
135 | reflect_output_remainder_c::value, final_xor_mask_c::value }; |
136 | |
137 | return result; |
138 | } |
139 | |
140 | static computer_type make_crc_optimal() |
141 | { return boost::crc_optimal<register_length_c::value, |
142 | divisor_polynominal_c::value, initial_remainder_c::value, |
143 | final_xor_mask_c::value, reflect_input_byte_c::value, |
144 | reflect_output_remainder_c::value>(); } |
145 | }; |
146 | |
147 | template < std::size_t Bits, boost::uintmax_t DivisorPolynominal, |
148 | boost::uintmax_t InitialRemainder, bool ReflectInputBytes, |
149 | bool ReflectOutputRemainder, boost::uintmax_t FinalXorMask, |
150 | boost::uintmax_t StandardTestDataResult > |
151 | class my_crc_test_traits |
152 | { |
153 | public: |
154 | typedef my_crc_ct_traits<Bits, DivisorPolynominal, InitialRemainder, |
155 | ReflectInputBytes, ReflectOutputRemainder, FinalXorMask> ct_traits_type; |
156 | typedef my_crc_rt_traits<Bits> rt_traits_type; |
157 | |
158 | typedef typename rt_traits_type::register_type register_type; |
159 | |
160 | typedef boost::integral_constant<std::size_t, Bits> register_length_c; |
161 | typedef boost::integral_constant<register_type, DivisorPolynominal> |
162 | divisor_polynominal_c; |
163 | typedef boost::integral_constant<register_type, InitialRemainder> |
164 | initial_remainder_c; |
165 | typedef boost::integral_constant<bool, ReflectInputBytes> reflect_input_byte_c; |
166 | typedef boost::integral_constant<bool, ReflectOutputRemainder> |
167 | reflect_output_remainder_c; |
168 | typedef boost::integral_constant<register_type, FinalXorMask> |
169 | final_xor_mask_c; |
170 | typedef boost::integral_constant<register_type, StandardTestDataResult> |
171 | standard_test_data_CRC_c; |
172 | |
173 | typedef typename ct_traits_type::computer_type computer_ct_type; |
174 | typedef typename rt_traits_type::computer_type computer_rt_type; |
175 | |
176 | static computer_ct_type make_crc_optimal() |
177 | { return ct_traits_type::make_crc_optimal(); } |
178 | static computer_rt_type make_crc_basic() |
179 | { return ct_traits_type().operator rt_traits_type().make_crc_basic(); } |
180 | }; |
181 | |
182 | // Now make some example CRC profiles |
183 | typedef my_crc_test_traits<16u, 0x8005u, 0u, true, true, 0u, std_crc_16_result> |
184 | my_crc_16_traits; |
185 | typedef my_crc_test_traits<16u, 0x1021u, 0xFFFFu, false, false, 0u, |
186 | std_crc_ccitt_false_result> my_crc_ccitt_false_traits; |
187 | typedef my_crc_test_traits<16u, 0x1021u, 0u, true, true, 0u, |
188 | std_crc_ccitt_true_result> my_crc_ccitt_true_traits; |
189 | typedef my_crc_test_traits<16u, 0x1021u, 0u, false, false, 0u, |
190 | std_crc_xmodem_result> my_crc_xmodem_traits; |
191 | typedef my_crc_test_traits<32u, 0x04C11DB7ul, 0xFFFFFFFFul, true, true, |
192 | 0xFFFFFFFFul, std_crc_32_result> my_crc_32_traits; |
193 | |
194 | template<class Test> |
195 | void run_crc_test_policies() |
196 | { |
197 | Test()(my_crc_16_traits()); |
198 | Test()(my_crc_ccitt_false_traits()); |
199 | Test()(my_crc_ccitt_true_traits()); |
200 | Test()(my_crc_xmodem_traits()); |
201 | Test()(my_crc_32_traits()); |
202 | } |
203 | |
204 | // Need to test when ReflectInputBytes and ReflectOutputRemainder differ |
205 | // (Grabbed from table at <http://regregex.bbcmicro.net/crc-catalogue.htm>.) |
206 | typedef my_crc_test_traits<6u, 0x19u, 0u, true, false, 0u, 0x19u> |
207 | my_crc_6_darc_traits; |
208 | typedef my_crc_test_traits<12u, 0x80Fu, 0u, false, true, 0u, 0xDAFu> |
209 | my_crc_12_3gpp_traits; |
210 | |
211 | template<class Test> |
212 | void run_crc_extended_test_policies() |
213 | { |
214 | Test()(my_crc_16_traits()); |
215 | Test()(my_crc_ccitt_false_traits()); |
216 | Test()(my_crc_ccitt_true_traits()); |
217 | Test()(my_crc_xmodem_traits()); |
218 | Test()(my_crc_32_traits()); |
219 | #if CONTROL_SUB_BYTE_MISMATCHED_REFLECTION_TEST |
220 | Test()(my_crc_6_darc_traits()); |
221 | #endif |
222 | Test()(my_crc_12_3gpp_traits()); |
223 | } |
224 | |
225 | // Bit mask constants |
226 | template < std::size_t BitIndex > |
227 | struct high_bit_mask_c |
228 | : boost::detail::high_bit_mask_c<BitIndex> |
229 | {}; |
230 | template < std::size_t BitCount > |
231 | struct low_bits_mask_c |
232 | : boost::detail::low_bits_mask_c<BitCount> |
233 | {}; |
234 | |
235 | } // anonymous namespace |
236 | |
237 | |
238 | // Unit tests ---------------------------------------------------------------// |
239 | |
240 | struct computation_comparison_test { |
241 | template<class CRCPolicy> |
242 | void operator()(CRCPolicy) |
243 | { |
244 | BOOST_AUTO( crc_f, CRCPolicy::make_crc_optimal() ); |
245 | BOOST_AUTO( crc_s, CRCPolicy::make_crc_basic() ); |
246 | typename CRCPolicy::register_type const func_result |
247 | = boost::crc<CRCPolicy::register_length_c::value, |
248 | CRCPolicy::divisor_polynominal_c::value, |
249 | CRCPolicy::initial_remainder_c::value, |
250 | CRCPolicy::final_xor_mask_c::value, |
251 | CRCPolicy::reflect_input_byte_c::value, |
252 | CRCPolicy::reflect_output_remainder_c::value>( std_data, std_data_len ); |
253 | |
254 | crc_f.process_bytes( std_data, std_data_len ); |
255 | crc_s.process_bytes( std_data, std_data_len ); |
256 | |
257 | BOOST_TEST_EQ( crc_f.checksum(), |
258 | CRCPolicy::standard_test_data_CRC_c::value ); |
259 | BOOST_TEST_EQ( crc_s.checksum(), |
260 | CRCPolicy::standard_test_data_CRC_c::value ); |
261 | BOOST_TEST_EQ( CRCPolicy::standard_test_data_CRC_c::value, |
262 | func_result ); |
263 | } |
264 | }; |
265 | |
266 | struct accessor_and_split_run_test { |
267 | template<class CRCPolicy> |
268 | void operator()(CRCPolicy) |
269 | { |
270 | typedef typename CRCPolicy::computer_ct_type optimal_crc_type; |
271 | typedef typename CRCPolicy::computer_rt_type basic_crc_type; |
272 | |
273 | // Test accessors |
274 | optimal_crc_type faster_crc1; |
275 | basic_crc_type slower_crc1( faster_crc1.get_truncated_polynominal(), |
276 | faster_crc1.get_initial_remainder(), faster_crc1.get_final_xor_value(), |
277 | faster_crc1.get_reflect_input(), faster_crc1.get_reflect_remainder() ); |
278 | |
279 | BOOST_TEST_EQ( faster_crc1.get_interim_remainder(), |
280 | slower_crc1.get_initial_remainder() ); |
281 | |
282 | // Process the first half of the standard data |
283 | std::size_t const mid_way = std_data_len / 2u; |
284 | |
285 | faster_crc1.process_bytes( std_data, mid_way ); |
286 | slower_crc1.process_bytes( std_data, mid_way ); |
287 | |
288 | BOOST_TEST_EQ( faster_crc1.checksum(), slower_crc1.checksum() ); |
289 | |
290 | // Process the second half of the standard data, testing more accessors |
291 | unsigned char const * const std_data_end = std_data + std_data_len; |
292 | boost::crc_optimal<optimal_crc_type::bit_count, |
293 | optimal_crc_type::truncated_polynominal, |
294 | optimal_crc_type::initial_remainder, optimal_crc_type::final_xor_value, |
295 | optimal_crc_type::reflect_input, optimal_crc_type::reflect_remainder> |
296 | faster_crc2( faster_crc1.get_interim_remainder() ); |
297 | boost::crc_basic<basic_crc_type::bit_count> slower_crc2( |
298 | slower_crc1.get_truncated_polynominal(), |
299 | slower_crc1.get_interim_remainder(), slower_crc1.get_final_xor_value(), |
300 | slower_crc1.get_reflect_input(), slower_crc1.get_reflect_remainder() ); |
301 | |
302 | faster_crc2.process_block( std_data + mid_way, std_data_end ); |
303 | slower_crc2.process_block( std_data + mid_way, std_data_end ); |
304 | |
305 | BOOST_TEST_EQ( slower_crc2.checksum(), faster_crc2.checksum() ); |
306 | BOOST_TEST_EQ( faster_crc2.checksum(), |
307 | CRCPolicy::standard_test_data_CRC_c::value ); |
308 | BOOST_TEST_EQ( CRCPolicy::standard_test_data_CRC_c::value, |
309 | slower_crc2.checksum() ); |
310 | } |
311 | }; |
312 | |
313 | struct reset_and_single_bit_error_test { |
314 | template<class CRCPolicy> |
315 | void operator()(CRCPolicy) |
316 | { |
317 | // A single-bit error in a CRC can be guaranteed to be detected if the |
318 | // modulo-2 polynomial divisor has at least two non-zero coefficients. The |
319 | // implicit highest coefficient is always one, so that leaves an explicit |
320 | // coefficient, i.e. at least one of the polynomial's bits is set. |
321 | BOOST_TEST( CRCPolicy::divisor_polynominal_c::value & |
322 | low_bits_mask_c<CRCPolicy::register_length_c::value>::value ); |
323 | |
324 | // Create a random block of data |
325 | boost::uint32_t ran_data[ 256 ]; |
326 | std::size_t const ran_length = sizeof(ran_data) / sizeof(ran_data[0]); |
327 | |
328 | std::generate_n( first: ran_data, n: ran_length, gen: boost::minstd_rand() ); |
329 | |
330 | // Create computers and compute the checksum of the data |
331 | BOOST_AUTO( optimal_tester, CRCPolicy::make_crc_optimal() ); |
332 | BOOST_AUTO( basic_tester, CRCPolicy::make_crc_basic() ); |
333 | |
334 | optimal_tester.process_bytes( ran_data, sizeof(ran_data) ); |
335 | basic_tester.process_bytes( ran_data, sizeof(ran_data) ); |
336 | |
337 | BOOST_AUTO( const optimal_checksum, optimal_tester.checksum() ); |
338 | BOOST_AUTO( const basic_checksum, basic_tester.checksum() ); |
339 | |
340 | BOOST_TEST_EQ( optimal_checksum, basic_checksum ); |
341 | |
342 | // Do the checksum again, while testing the capability to reset the current |
343 | // remainder (to either a default or a given value) |
344 | optimal_tester.reset(); |
345 | basic_tester.reset( CRCPolicy::initial_remainder_c::value ); |
346 | |
347 | optimal_tester.process_bytes( ran_data, sizeof(ran_data) ); |
348 | basic_tester.process_bytes( ran_data, sizeof(ran_data) ); |
349 | |
350 | BOOST_TEST_EQ( optimal_tester.checksum(), basic_tester.checksum() ); |
351 | BOOST_TEST_EQ( optimal_tester.checksum(), optimal_checksum ); |
352 | BOOST_TEST_EQ( basic_tester.checksum(), basic_checksum ); |
353 | |
354 | // Introduce a single-bit error |
355 | ran_data[ ran_data[0] % ran_length ] ^= ( 1u << (ran_data[ 1 ] % 32u) ); |
356 | |
357 | // Compute the checksum of the errorenous data, while continuing to test |
358 | // the remainder-resetting methods |
359 | optimal_tester.reset( CRCPolicy::initial_remainder_c::value ); |
360 | basic_tester.reset(); |
361 | |
362 | optimal_tester.process_bytes( ran_data, sizeof(ran_data) ); |
363 | basic_tester.process_bytes( ran_data, sizeof(ran_data) ); |
364 | |
365 | BOOST_TEST_EQ( basic_tester.checksum(), optimal_tester.checksum() ); |
366 | BOOST_TEST_NE( optimal_checksum, optimal_tester.checksum() ); |
367 | BOOST_TEST_NE( basic_checksum, basic_tester.checksum() ); |
368 | } |
369 | }; |
370 | |
371 | void augmented_crc_test() |
372 | { |
373 | using std::size_t; |
374 | using boost::uint32_t; |
375 | using boost::augmented_crc; |
376 | |
377 | // Common CRC parameters, all others are zero/false |
378 | static size_t const bits = 32u; |
379 | static uint32_t const poly = 0x04C11DB7ul; |
380 | |
381 | // Create a random block of data, with space at the end for a CRC |
382 | static size_t const data_length = 256u; |
383 | static size_t const run_length = data_length + 1u; |
384 | |
385 | uint32_t run_data[ run_length ]; |
386 | uint32_t & run_crc = run_data[ data_length ]; |
387 | size_t const data_size = sizeof( run_data ) - sizeof( run_crc ); |
388 | |
389 | std::generate_n( first: run_data, n: data_length, gen: boost::minstd_rand() ); |
390 | run_crc = 0u; |
391 | |
392 | // The augmented-CRC routine needs to push an appropriate number of zero |
393 | // bits (the register size) through before the checksum can be extracted. |
394 | // The other CRC methods, which are un-augmented, don't need to do this. |
395 | uint32_t const checksum = boost::crc<bits, poly, 0u, 0u, false, false>( |
396 | buffer: run_data, byte_count: data_size ); |
397 | |
398 | BOOST_TEST_EQ( (augmented_crc<bits, poly>)(run_data, sizeof( run_data |
399 | )), checksum ); |
400 | |
401 | // Now appending a message's CRC to the message should lead to a zero-value |
402 | // checksum. Note that the CRC must be read from the largest byte on down, |
403 | // i.e. big-endian! |
404 | run_crc = native_to_big( x: checksum ); |
405 | BOOST_TEST_EQ( (augmented_crc<bits, poly>)(run_data, sizeof( run_data |
406 | )), 0u ); |
407 | |
408 | // Check again with the non-augmented methods |
409 | boost::crc_basic<bits> crc_b( poly ); |
410 | |
411 | crc_b.process_bytes( buffer: run_data, byte_count: data_size ); |
412 | BOOST_TEST_EQ( crc_b.checksum(), checksum ); |
413 | |
414 | // Introduce a single-bit error, now the checksum shouldn't match! |
415 | uint32_t const affected_word_index = run_data[ 0 ] % data_length; |
416 | uint32_t const affected_bit_index = run_data[ 1 ] % 32u; |
417 | uint32_t const affecting_mask = 1ul << affected_bit_index; |
418 | |
419 | run_data[ affected_word_index ] ^= affecting_mask; |
420 | |
421 | crc_b.reset(); |
422 | crc_b.process_bytes( buffer: run_data, byte_count: data_size ); |
423 | BOOST_TEST_NE( crc_b.checksum(), checksum ); |
424 | |
425 | BOOST_TEST_NE( (augmented_crc<bits, poly>)(run_data, sizeof( run_data )), |
426 | 0u ); |
427 | |
428 | run_crc = 0u; |
429 | BOOST_TEST_NE( (augmented_crc<bits, poly>)(run_data, sizeof( run_data )), |
430 | checksum ); |
431 | |
432 | // Now introduce the single error in the checksum instead |
433 | run_data[ affected_word_index ] ^= affecting_mask; |
434 | run_crc = native_to_big( x: checksum ) ^ affecting_mask; |
435 | BOOST_TEST_NE( (augmented_crc<bits, poly>)(run_data, sizeof( run_data )), |
436 | 0u ); |
437 | |
438 | // Repeat these tests with a non-zero initial remainder. Before we can |
439 | // check the results against a non-augmented CRC computer, realize that they |
440 | // interpret the inital remainder differently. However, the two standards |
441 | // can convert between each other. |
442 | // (checksum2 initial value is as a scratch pad. So are the address and new |
443 | // value of run_crc, but it's also useful for the next sub-step.) |
444 | // (TODO: getting the equivalent unaugmented-CRC initial-remainder given an |
445 | // augmented-CRC initial-remainder is done by putting said augmented-CRC |
446 | // initial-remainder through the augmented-CRC computation with a |
447 | // zero-value message. I don't know how to go the other way, yet.) |
448 | run_crc = 0u; |
449 | uint32_t checksum2 = run_data[ run_data[2] % data_length ]; |
450 | uint32_t const initial_residue = checksum2 + !checksum2; // ensure nonzero |
451 | uint32_t const initial_residue_unaugmented = augmented_crc<bits, poly>( |
452 | buffer: &run_crc, byte_count: sizeof(run_crc), initial_remainder: initial_residue ); |
453 | |
454 | BOOST_TEST_NE( initial_residue, 0u ); |
455 | crc_b.reset( new_rem: initial_residue_unaugmented ); |
456 | crc_b.process_bytes( buffer: run_data, byte_count: data_size ); |
457 | checksum2 = crc_b.checksum(); |
458 | |
459 | BOOST_TEST_EQ( run_crc, 0u ); |
460 | BOOST_TEST_EQ( (augmented_crc<bits, poly>)(run_data, sizeof( run_data ), |
461 | initial_residue), checksum2 ); |
462 | run_crc = native_to_big( x: checksum2 ); |
463 | BOOST_TEST_EQ( (augmented_crc<bits, poly>)(run_data, sizeof( run_data ), |
464 | initial_residue), 0u ); |
465 | |
466 | // Use the inital remainder argument to split a CRC-computing run |
467 | size_t const split_index = data_length / 2u; |
468 | uint32_t const intermediate = augmented_crc<bits, poly>( buffer: run_data, |
469 | byte_count: sizeof(run_crc) * split_index, initial_remainder: initial_residue ); |
470 | |
471 | BOOST_TEST_EQ( (augmented_crc<bits, poly>)(&run_data[ split_index ], |
472 | sizeof( run_data ) - sizeof( run_crc ) * split_index, intermediate), 0u ); |
473 | run_crc = 0u; |
474 | BOOST_TEST_EQ( (augmented_crc<bits, poly>)(&run_data[ split_index ], |
475 | sizeof( run_data ) - sizeof( run_crc ) * split_index, intermediate), |
476 | checksum2 ); |
477 | |
478 | // Repeat the single-bit error test, with a non-zero initial-remainder |
479 | run_data[ run_data[3] % data_length ] ^= ( 1ul << (run_data[4] % 32u) ); |
480 | run_crc = native_to_big( x: checksum2 ); |
481 | BOOST_TEST_NE( (augmented_crc<bits, poly>)(run_data, sizeof( run_data ), |
482 | initial_residue), 0u ); |
483 | } |
484 | |
485 | // Optimal computer, via the single-run function |
486 | unsigned crc_f1( const void * buffer, std::size_t byte_count ) |
487 | { |
488 | return boost::crc<3u, 0x03u, 0u, 0u, false, false>( buffer, byte_count ); |
489 | } |
490 | |
491 | void sub_nybble_polynominal_test() |
492 | { |
493 | // The CRC standard is a SDH/SONET Low Order LCAS control word with CRC-3 |
494 | // taken from ITU-T G.707 (12/03) XIII.2. |
495 | |
496 | // Four samples, each four bytes; should all have a CRC of zero |
497 | unsigned char const samples[4][4] |
498 | = { |
499 | { 0x3Au, 0xC4u, 0x08u, 0x06u }, |
500 | { 0x42u, 0xC5u, 0x0Au, 0x41u }, |
501 | { 0x4Au, 0xC5u, 0x08u, 0x22u }, |
502 | { 0x52u, 0xC4u, 0x08u, 0x05u } |
503 | }; |
504 | |
505 | // Basic computer |
506 | boost::crc_basic<3u> crc_1( 0x03u ); |
507 | |
508 | crc_1.process_bytes( buffer: samples[0], byte_count: 4u ); |
509 | BOOST_TEST_EQ( crc_1.checksum(), 0u ); |
510 | |
511 | crc_1.reset(); |
512 | crc_1.process_bytes( buffer: samples[1], byte_count: 4u ); |
513 | BOOST_TEST_EQ( crc_1.checksum(), 0u ); |
514 | |
515 | crc_1.reset(); |
516 | crc_1.process_bytes( buffer: samples[2], byte_count: 4u ); |
517 | BOOST_TEST_EQ( crc_1.checksum(), 0u ); |
518 | |
519 | crc_1.reset(); |
520 | crc_1.process_bytes( buffer: samples[3], byte_count: 4u ); |
521 | BOOST_TEST_EQ( crc_1.checksum(), 0u ); |
522 | |
523 | BOOST_TEST_EQ( crc_f1(samples[ 0 ], 4u), 0u ); |
524 | BOOST_TEST_EQ( crc_f1(samples[ 1 ], 4u), 0u ); |
525 | BOOST_TEST_EQ( crc_f1(samples[ 2 ], 4u), 0u ); |
526 | BOOST_TEST_EQ( crc_f1(samples[ 3 ], 4u), 0u ); |
527 | |
528 | // TODO: do similar tests with boost::augmented_crc<3, 0x03> |
529 | // (Now I think that this can't be done right now, since that function reads |
530 | // byte-wise, so the register size needs to be a multiple of CHAR_BIT.) |
531 | } |
532 | |
533 | // Optimal computer, via the single-run function |
534 | unsigned crc_f2( const void * buffer, std::size_t byte_count ) |
535 | { |
536 | return boost::crc<7u, 0x09u, 0u, 0u, false, false>( buffer, byte_count ); |
537 | } |
538 | |
539 | void sub_octet_polynominal_test() |
540 | { |
541 | // The CRC standard is a SDH/SONET J0/J1/J2/N1/N2/TR TTI (trace message) |
542 | // with CRC-7, o.a. ITU-T G.707 Annex B, G.832 Annex A. |
543 | |
544 | // Two samples, each sixteen bytes |
545 | // Sample 1 is '\x80' + ASCII("123456789ABCDEF") |
546 | // Sample 2 is '\x80' + ASCII("TTI UNAVAILABLE") |
547 | unsigned char const samples[2][16] |
548 | = { |
549 | { 0x80u, 0x31u, 0x32u, 0x33u, 0x34u, 0x35u, 0x36u, 0x37u, 0x38u, |
550 | 0x39u, 0x41u, 0x42u, 0x43u, 0x44u, 0x45u, 0x46u }, |
551 | { 0x80u, 0x54u, 0x54u, 0x49u, 0x20u, 0x55u, 0x4Eu, 0x41u, 0x56u, |
552 | 0x41u, 0x49u, 0x4Cu, 0x41u, 0x42u, 0x4Cu, 0x45u } |
553 | }; |
554 | unsigned const results[2] = { 0x62u, 0x23u }; |
555 | |
556 | // Basic computer |
557 | boost::crc_basic<7u> crc_1( 0x09u ); |
558 | |
559 | crc_1.process_bytes( buffer: samples[0], byte_count: 16u ); |
560 | BOOST_TEST_EQ( crc_1.checksum(), results[0] ); |
561 | |
562 | crc_1.reset(); |
563 | crc_1.process_bytes( buffer: samples[1], byte_count: 16u ); |
564 | BOOST_TEST_EQ( crc_1.checksum(), results[1] ); |
565 | |
566 | BOOST_TEST_EQ( crc_f2(samples[ 0 ], 16u), results[0] ); |
567 | BOOST_TEST_EQ( crc_f2(samples[ 1 ], 16u), results[1] ); |
568 | |
569 | // TODO: do similar tests with boost::augmented_crc<7, 0x09> |
570 | // (Now I think that this can't be done right now, since that function reads |
571 | // byte-wise, so the register size needs to be a multiple of CHAR_BIT.) |
572 | } |
573 | |
574 | void one_bit_polynominal_test() |
575 | { |
576 | // Try a CRC based on the (x + 1) polynominal, which is a factor in |
577 | // many real-life polynominals and doesn't fit evenly in a byte. |
578 | boost::crc_basic<1u> crc_1( 1u ); |
579 | |
580 | crc_1.process_bytes( buffer: std_data, byte_count: std_data_len ); |
581 | BOOST_TEST_EQ( crc_1.checksum(), 1u ); |
582 | |
583 | // Do it again, but using crc_optimal. The real purpose of this is to test |
584 | // crc_optimal::process_byte, which doesn't get exercised anywhere else in |
585 | // this file (directly or indirectly). |
586 | boost::crc_optimal<1u, 1u, 0u, 0u, false, false> crc_2; |
587 | |
588 | for ( std::size_t i = 0u ; i < std_data_len ; ++i ) |
589 | crc_2.process_byte( byte: std_data[i] ); |
590 | BOOST_TEST_EQ( crc_2.checksum(), 1u ); |
591 | } |
592 | |
593 | struct function_object_test { |
594 | template<class CRCPolicy> |
595 | void operator()(CRCPolicy) |
596 | { |
597 | typename CRCPolicy::computer_ct_type crc_c; |
598 | |
599 | crc_c = std::for_each( std_data, std_data + std_data_len, crc_c ); |
600 | BOOST_TEST_EQ( crc_c(), CRCPolicy::standard_test_data_CRC_c::value ); |
601 | } |
602 | }; |
603 | |
604 | // Ticket #2492: crc_optimal with reversed CRC16 |
605 | // <https://svn.boost.org/trac/boost/ticket/2492> |
606 | void issue_2492_test() |
607 | { |
608 | // I'm trusting that the original bug reporter got his/her calculations |
609 | // correct. |
610 | boost::uint16_t const expected_result = 0xF990u; |
611 | |
612 | boost::crc_optimal<16, 0x100Bu, 0xFFFFu, 0x0000, true, false> boost_crc_1; |
613 | boost::crc_basic<16> boost_crc_2( 0x100Bu, 0xFFFFu, 0x0000, true, false ); |
614 | |
615 | // This should be right... |
616 | boost_crc_1.process_byte( byte: 0u ); |
617 | BOOST_TEST_EQ( boost_crc_1.checksum(), expected_result ); |
618 | |
619 | // ...but the reporter said this didn't reflect, giving 0x099F as the |
620 | // (wrong) result. However, I get the right answer! |
621 | boost_crc_2.process_byte( byte: 0u ); |
622 | BOOST_TEST_EQ( boost_crc_2.checksum(), expected_result ); |
623 | } |
624 | |
625 | int main() |
626 | { |
627 | run_crc_extended_test_policies<computation_comparison_test>(); |
628 | run_crc_test_policies<accessor_and_split_run_test>(); |
629 | run_crc_test_policies<reset_and_single_bit_error_test>(); |
630 | augmented_crc_test(); |
631 | sub_nybble_polynominal_test(); |
632 | sub_octet_polynominal_test(); |
633 | one_bit_polynominal_test(); |
634 | run_crc_test_policies<function_object_test>(); |
635 | issue_2492_test(); |
636 | return boost::report_errors(); |
637 | } |
638 | |