Squashed 'third_party/pycrc/' content from commit cb91196b9
Change-Id: Iaed6f7d683e3c11395f10f0724f973363aad2cdb
git-subtree-dir: third_party/pycrc
git-subtree-split: cb91196b920d1f892c05941ed470c7a80cba7596
diff --git a/test/check_files.sh b/test/check_files.sh
new file mode 100755
index 0000000..4cc874f
--- /dev/null
+++ b/test/check_files.sh
@@ -0,0 +1,116 @@
+#!/bin/sh
+set -e
+
+PYCRC=`dirname $0`/../pycrc.py
+outdir_old="/tmp/pycrc_out"
+outdir_new="/tmp/pycrc_new"
+tarfile="pycrc_files.tar.gz"
+
+usage() {
+ echo >&2 "usage: $0 [OPTIONS]"
+ echo >&2 ""
+ echo >&2 "with OPTIONS in"
+ echo >&2 " -c check the generated output"
+ echo >&2 " -g generate the database"
+ echo >&2 " -n no cleanup: don't delete the directories with the generated code"
+ echo >&2 " -h this help message"
+}
+
+
+opt_check=off
+opt_no_cleanup=off
+opt_generate=off
+
+while getopts cgnh opt; do
+ case "$opt" in
+ c) opt_check=on;;
+ g) opt_generate=on;;
+ n) opt_no_cleanup=on;;
+ h) usage
+ exit 0
+ ;;
+ \?) usage # unknown flag
+ exit 1
+ ;;
+ esac
+done
+shift `expr $OPTIND - 1`
+
+if [ -e "$outdir_old" ]; then
+ echo >&2 "Output directory $outdir_old exists!"
+ exit 1
+fi
+if [ -e "$outdir_new" ]; then
+ echo >&2 "Output directory $outdir_new exists!"
+ exit 1
+fi
+
+
+cleanup() {
+ if [ "$opt_no_cleanup" = "on" ]; then
+ echo "No cleanup. Please delete $outdir_old and $outdir_new when you're done"
+ else
+ rm -rf "$outdir_old" "$outdir_new"
+ fi
+}
+
+trap cleanup 0 1 2 3 15
+
+
+generate() {
+ outfile="$1"
+ shift
+ $PYCRC "$@" -o "${outfile}"
+ sed -i -e 's/Generated on ... ... .. ..:..:.. ..../Generated on XXX XXX XX XX:XX:XX XXXX/; s/by pycrc v[0-9.]*/by pycrc vXXX/;' "${outfile}"
+}
+
+populate() {
+ outdir=$1
+ mkdir -p "$outdir"
+ models=`PYTHONPATH=.. python -c 'import pycrc.models as m; print(" ".join(m.CrcModels().names()))'`
+ for model in "undefined" $models; do
+ for algo in "bbb" "bbf" "tbl"; do
+ for cstd in c98 c99; do
+ if [ "$model" = "undefined" ]; then
+ mod_opt=
+ else
+ mod_opt="--model=${model}"
+ fi
+ generate "${outdir}/${model}_${algo}_${cstd}.h" --generate=h --algorithm=${algo} $mod_opt
+ generate "${outdir}/${model}_${algo}_${cstd}.c" --generate=c --algorithm=${algo} $mod_opt
+ done
+ done
+ done
+
+ algo=tbl
+ for model in crc-32; do
+ for slice in 4 8 16; do
+ for cstd in c98 c99; do
+ generate "${outdir}/${model}_${algo}_sb${slice}_${cstd}.h" --generate=h --algorithm=${algo} --model=${model} --slice-by ${slice}
+ generate "${outdir}/${model}_${algo}_sb${slice}_${cstd}.c" --generate=c --algorithm=${algo} --model=${model} --slice-by ${slice}
+ done
+ done
+ done
+}
+
+do_check() {
+ tar xzf "$tarfile" -C "`dirname $outdir_new`"
+ populate "$outdir_new"
+ diff -ru "$outdir_old" "$outdir_new"
+}
+
+
+if [ "$opt_check" = "on" ]; then
+ if [ ! -f "$tarfile" ]; then
+ echo >&2 "Can't find tarfile $tarfile"
+ exit 1
+ fi
+ do_check
+fi
+
+if [ "$opt_generate" = "on" ]; then
+ populate "$outdir_old"
+ dirname="`dirname $outdir_old`"
+ basename="`basename $outdir_old`"
+ tar czf "$tarfile" -C "$dirname" "$basename"
+fi
diff --git a/test/main.c b/test/main.c
new file mode 100644
index 0000000..252d4fd
--- /dev/null
+++ b/test/main.c
@@ -0,0 +1,283 @@
+// Copyright (c) 2006-2013 Thomas Pircher <tehpeh-web@tty1.net>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "crc.h"
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <string.h>
+
+static bool atob(const char *str);
+static crc_t xtoi(const char *str);
+static int get_config(int argc, char *argv[], crc_cfg_t *cfg);
+#if CRC_ALGO_BIT_BY_BIT
+static crc_t crc_verify(const crc_cfg_t *cfg, crc_t crc_pre_final, crc_t crc);
+static crc_t crc_reflect(crc_t data, size_t data_len);
+#endif
+
+
+
+static bool verbose = false;
+static unsigned char str[256] = "123456789";
+
+bool atob(const char *str)
+{
+ if (!str) {
+ return 0;
+ }
+ if (isdigit(str[0])) {
+ return (bool)atoi(str);
+ }
+ if (tolower(str[0]) == 't') {
+ return true;
+ }
+ return false;
+}
+
+crc_t xtoi(const char *str)
+{
+ crc_t ret = 0;
+
+ if (!str) {
+ return 0;
+ }
+ if (str[0] == '0' && tolower(str[1]) == 'x') {
+ str += 2;
+ while (*str) {
+ if (isdigit(*str))
+ ret = 16 * ret + *str - '0';
+ else if (isxdigit(*str))
+ ret = 16 * ret + tolower(*str) - 'a' + 10;
+ else
+ return ret;
+ str++;
+ }
+ } else if (isdigit(*str)) {
+ while (*str) {
+ if (isdigit(*str))
+ ret = 10 * ret + *str - '0';
+ else
+ return ret;
+ str++;
+ }
+ }
+ return ret;
+}
+
+
+int get_config(int argc, char *argv[], crc_cfg_t *cfg)
+{
+ int c;
+ int option_index;
+ static struct option long_options[] = {
+ {"width", 1, 0, 'w'},
+ {"poly", 1, 0, 'p'},
+ {"reflect-in", 1, 0, 'n'},
+ {"xor-in", 1, 0, 'i'},
+ {"reflect-out", 1, 0, 'u'},
+ {"xor-out", 1, 0, 'o'},
+ {"verbose", 0, 0, 'v'},
+ {"check-string", 1, 0, 's'},
+ {"table-idx-with", 1, 0, 't'},
+ {0, 0, 0, 0}
+ };
+
+ while (1) {
+ option_index = 0;
+
+ c = getopt_long(argc, argv, "w:p:ni:uo:v", long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 0:
+ printf("option %s", long_options[option_index].name);
+ if (optarg)
+ printf(" with arg %s", optarg);
+ printf ("\n");
+ case 'w':
+ cfg->width = atoi(optarg);
+ break;
+ case 'p':
+ cfg->poly = xtoi(optarg);
+ break;
+ case 'n':
+ cfg->reflect_in = atob(optarg);
+ break;
+ case 'i':
+ cfg->xor_in = xtoi(optarg);
+ break;
+ case 'u':
+ cfg->reflect_out = atob(optarg);
+ break;
+ case 'o':
+ cfg->xor_out = xtoi(optarg);
+ break;
+ case 's':
+ memcpy(str, optarg, strlen(optarg) < sizeof(str) ? strlen(optarg) + 1 : sizeof(str));
+ str[sizeof(str) - 1] = '\0';
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 't':
+ // ignore --table_idx_width option
+ break;
+ case '?':
+ return -1;
+ case ':':
+ fprintf(stderr, "missing argument to option %c\n", c);
+ return -1;
+ default:
+ fprintf(stderr, "unhandled option %c\n", c);
+ return -1;
+ }
+ }
+ cfg->msb_mask = (crc_t)1u << (cfg->width - 1);
+ cfg->crc_mask = (cfg->msb_mask - 1) | cfg->msb_mask;
+ cfg->crc_shift = cfg->width < 8 ? 8 - cfg->width : 0;
+
+ cfg->poly &= cfg->crc_mask;
+ cfg->xor_in &= cfg->crc_mask;
+ cfg->xor_out &= cfg->crc_mask;
+ return 0;
+}
+
+
+#if CRC_ALGO_BIT_BY_BIT
+crc_t crc_verify(const crc_cfg_t *cfg, crc_t crc_pre_final, crc_t crc)
+{
+ crc_t result;
+ unsigned char data;
+ unsigned int i;
+
+ // don't verify if the width is not a multiple of 8
+ if (cfg->width % 8) {
+ return 0;
+ }
+ if (cfg->xor_out) {
+ crc ^= cfg->xor_out;
+ }
+ if (cfg->reflect_out) {
+ crc = crc_reflect(crc, cfg->width);
+ }
+ result = crc_pre_final;
+ for (i = 0; i < cfg->width / 8; i++) {
+ data = (crc >> (cfg->width - 8 * i - 8)) & 0xff;
+ if (cfg->reflect_in) {
+ data = crc_reflect(data, 8);
+ }
+ result = crc_update(cfg, result, &data, 1);
+ }
+ // no crc_finalize, because if the CRC calculation is correct, result == 0.
+ // A crc_finalize would XOR-in again some ones into the solution.
+ // In theory the finalize function of the bit-by-bit algorithm
+ // would also loop over cfg->width zero bits, but since
+ // a) result == 0, and
+ // b) input data == 0
+ // the output would always be zero
+ return result;
+}
+
+crc_t crc_reflect(crc_t data, size_t data_len)
+{
+ unsigned int i;
+ crc_t ret;
+
+ ret = 0;
+ for (i = 0; i < data_len; i++)
+ {
+ if (data & 0x01) {
+ ret = (ret << 1) | 1;
+ } else {
+ ret = ret << 1;
+ }
+ data >>= 1;
+ }
+ return ret;
+}
+#endif // CRC_ALGO_BIT_BY_BIT
+
+
+int main(int argc, char *argv[])
+{
+ crc_cfg_t cfg = {
+ 0, // width
+ 0, // poly
+ 0, // xor_in
+ 0, // reflect_in
+ 0, // xor_out
+ 0, // reflect_out
+
+ 0, // crc_mask
+ 0, // msb_mask
+ 0, // crc_shift
+ };
+ crc_t crc;
+ crc_t crc_test, crc_pre_final;
+ char format[20];
+ int ret, i;
+
+ ret = get_config(argc, argv, &cfg);
+ if (ret == 0) {
+# if CRC_ALGO_TABLE_DRIVEN
+ crc_table_gen(&cfg);
+# endif // CRC_ALGO_TABLE_DRIVEN
+ crc = crc_init(&cfg);
+ crc = crc_pre_final = crc_update(&cfg, crc, str, strlen((char *)str));
+ crc = crc_finalize(&cfg, crc);
+
+# if CRC_ALGO_BIT_BY_BIT
+ if (crc_verify(&cfg, crc_pre_final, crc) != 0) {
+ fprintf(stderr, "error: crc verification failed\n");
+ return 1;
+ }
+# endif
+
+ // calculate the checksum again, but this time loop over the input
+ // bytes one-by-one.
+ crc_test = crc_init(&cfg);
+ for (i = 0; str[i]; i++)
+ {
+ crc_test = crc_update(&cfg, crc_test, str + i, 1);
+ }
+ crc_test = crc_finalize(&cfg, crc_test);
+ if (crc_test != crc) {
+ fprintf(stderr, "error: crc loop verification failed\n");
+ return 1;
+ }
+
+ if (verbose) {
+ snprintf(format, sizeof(format), "%%-16s = 0x%%0%dx\n", (unsigned int)(cfg.width + 3) / 4);
+ printf("%-16s = %d\n", "width", (unsigned int)cfg.width);
+ printf(format, "poly", (unsigned int)cfg.poly);
+ printf("%-16s = %s\n", "reflect_in", cfg.reflect_in ? "true": "false");
+ printf(format, "xor_in", cfg.xor_in);
+ printf("%-16s = %s\n", "reflect_out", cfg.reflect_out ? "true": "false");
+ printf(format, "xor_out", (unsigned int)cfg.xor_out);
+ printf(format, "crc_mask", (unsigned int)cfg.crc_mask);
+ printf(format, "msb_mask", (unsigned int)cfg.msb_mask);
+ }
+ printf("0x%llx\n", (unsigned long long int)crc);
+ }
+ return !ret;
+}
diff --git a/test/performance.sh b/test/performance.sh
new file mode 100755
index 0000000..7b6b239
--- /dev/null
+++ b/test/performance.sh
@@ -0,0 +1,147 @@
+#!/bin/sh
+set -e
+
+PYCRC=`dirname $0`/../pycrc.py
+
+cleanup() {
+ rm -f a.out performance.c crc_bbb.[ch] crc_bbf.[ch] crc_tb[l4].[ch] crc_sb4.[ch]
+}
+
+trap cleanup 0 1 2 3 15
+
+model=crc-32
+
+prefix=bbb
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo bit-by-bit
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo bit-by-bit
+prefix=bbf
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo bit-by-bit-fast
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo bit-by-bit-fast
+prefix=tbl
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo table-driven
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo table-driven
+prefix=tb4
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo table-driven --table-idx-width 4
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo table-driven --table-idx-width 4
+prefix=sb4
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate h -o crc_$prefix.h --algo table-driven --slice-by 4
+$PYCRC --model $model --symbol-prefix crc_${prefix}_ --generate c -o crc_$prefix.c --algo table-driven --slice-by 4
+
+
+print_main() {
+cat <<EOF
+#include "crc_bbb.h"
+#include "crc_bbf.h"
+#include "crc_tbl.h"
+#include "crc_tb4.h"
+#include "crc_sb4.h"
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/times.h>
+#include <unistd.h>
+
+#define NUM_RUNS (128*256*256)
+
+unsigned char buf[1024];
+
+void test_bbb(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+void test_bbf(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+void test_tbl(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+void test_tb4(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+void test_sb4(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec);
+
+/**
+ * Print results.
+ *
+ * \param dsc Description of the test
+ * \param buflen Length of one buffer
+ * \param num_runs Number of runs over that buffer
+ * \param t_user user time
+ * \param t_sys system time
+ * \return void
+ *****************************************************************************/
+void show_times(const char *dsc, size_t buflen, size_t num_runs, double t_user)
+{
+ double mbps = (((double)buflen) * num_runs)/(1024*1024*t_user);
+ printf("%s of %ld bytes (%ld * %ld)\n", dsc, (long)buflen*num_runs, (long)buflen, (long)num_runs);
+ printf("%13s: %7.3f s %13s: %7.3f MiB/s\n", "user time", t_user, "throughput", mbps);
+ printf("\n");
+}
+
+
+/**
+ * C main function.
+ *
+ * \retval 0 on success
+ * \retval 1 on failure
+ *****************************************************************************/
+int main(void)
+{
+ unsigned int i;
+ long int clock_per_sec;
+
+ for (i = 0; i < sizeof(buf); i++) {
+ buf[i] = (unsigned char)rand();
+ }
+ clock_per_sec = sysconf(_SC_CLK_TCK);
+
+ // bit-by-bit
+ test_bbb(buf, sizeof(buf), NUM_RUNS / 8, clock_per_sec);
+
+ // bit-by-bit-fast
+ test_bbf(buf, sizeof(buf), NUM_RUNS / 8, clock_per_sec);
+
+ // table-driven
+ test_tbl(buf, sizeof(buf), NUM_RUNS, clock_per_sec);
+
+ // table-driven idx4
+ test_tb4(buf, sizeof(buf), NUM_RUNS / 2, clock_per_sec);
+
+ // table-driven slice-by 4
+ test_sb4(buf, sizeof(buf), NUM_RUNS, clock_per_sec);
+
+ return 0;
+}
+EOF
+}
+
+print_routine() {
+ algo=$1
+ prefix=$2
+ cat <<EOF
+/**
+ * Test $algo Algorithm.
+ *
+ * \return void
+ *****************************************************************************/
+void test_${prefix}(unsigned char *buf, size_t buf_len, size_t num_runs, clock_t clock_per_sec)
+{
+ crc_${prefix}_t crc;
+ unsigned int i;
+ struct tms tm1, tm2;
+
+ times(&tm1);
+ crc = crc_${prefix}_init();
+ for (i = 0; i < num_runs; i++) {
+ crc = crc_${prefix}_update(crc, buf, buf_len);
+ }
+ crc = crc_${prefix}_finalize(crc);
+ times(&tm2);
+ show_times("$model, $algo, block-wise", buf_len, num_runs,
+ ((double)(tm2.tms_utime - tm1.tms_utime) / (double)clock_per_sec));
+}
+
+EOF
+}
+
+print_main > performance.c
+print_routine "bit-by-bit" bbb >> performance.c
+print_routine "bit-by-bit-fast" bbf >> performance.c
+print_routine "table-driven" tbl >> performance.c
+print_routine "table-driven idx4" tb4 >> performance.c
+print_routine "table-driven sb4" sb4 >> performance.c
+
+gcc -W -Wall -O3 crc_bbb.c crc_bbf.c crc_tbl.c crc_tb4.c crc_sb4.c performance.c
+./a.out
diff --git a/test/test.py b/test/test.py
new file mode 100644
index 0000000..1731416
--- /dev/null
+++ b/test/test.py
@@ -0,0 +1,679 @@
+#!/usr/bin/env python
+# -*- coding: Latin-1 -*-
+
+# pycrc test application.
+
+from optparse import OptionParser, Option, OptionValueError
+from copy import copy
+import os, sys
+import tempfile
+sys.path.append('..')
+sys.path.append('.')
+from pycrc.models import CrcModels
+from pycrc.algorithms import Crc
+
+
+class Options(object):
+ """
+ The options parsing and validating class
+ """
+
+ def __init__(self):
+ self.AllAlgorithms = set(['bit-by-bit', 'bbb', 'bit-by-bit-fast', 'bbf', 'table-driven', 'tbl'])
+ self.Compile = False
+ self.RandomParameters = False
+ self.CompileMixedArgs = False
+ self.VariableWidth = False
+ self.verbose = False
+ self.algorithm = copy(self.AllAlgorithms)
+
+ def parse(self, argv = None):
+ """
+ Parses and validates the options given as arguments
+ """
+ usage = """%prog [OPTIONS]"""
+
+ algorithms = ', '.join(sorted(list(self.AllAlgorithms)) + ['all'])
+ parser = OptionParser(usage=usage)
+ parser.add_option('-v', '--verbose',
+ action='store_true', dest='verbose', default=self.verbose,
+ help='print information about the model')
+ parser.add_option('-c', '--compile',
+ action='store_true', dest='compile', default=self.Compile,
+ help='test compiled version')
+ parser.add_option('-r', '--random-parameters',
+ action='store_true', dest='random_parameters', default=self.RandomParameters,
+ help='test random parameters')
+ parser.add_option('-m', '--compile-mixed-arguments',
+ action='store_true', dest='compile_mixed_args', default=self.CompileMixedArgs,
+ help='test compiled C program with some arguments given at compile time some arguments given at runtime')
+ parser.add_option('-w', '--variable-width',
+ action='store_true', dest='variable_width', default=self.VariableWidth,
+ help='test variable width from 1 to 64')
+ parser.add_option('-a', '--all',
+ action='store_true', dest='all', default=False,
+ help='do all tests')
+ parser.add_option('--algorithm',
+ action='store', type='string', dest='algorithm', default='all',
+ help='choose an algorithm from {{{0:s}}}'.format(algorithms, metavar='ALGO'))
+
+ (options, args) = parser.parse_args(argv)
+
+ self.verbose = options.verbose
+ self.Compile = options.all or options.compile or options.random_parameters
+ self.RandomParameters = options.all or options.random_parameters
+ self.CompileMixedArgs = options.all or options.compile_mixed_args
+ self.VariableWidth = options.all or options.variable_width
+
+ if options.algorithm is not None:
+ alg = options.algorithm.lower()
+ if alg in self.AllAlgorithms:
+ self.algorithm = set([alg])
+ elif alg == 'all':
+ self.algorithm = copy(self.AllAlgorithms)
+ else:
+ sys.stderr.write('unknown algorithm: {0:s}\n'.format(alg))
+ sys.exit(1)
+
+
+class CrcTests(object):
+ """
+ The CRC test class.
+ """
+
+ def __init__(self):
+ """
+ The class constructor.
+ """
+ self.pycrc_bin = '/bin/false'
+ self.use_algo_bit_by_bit = True
+ self.use_algo_bit_by_bit_fast = True
+ self.use_algo_table_driven = True
+ self.verbose = False
+ self.python3 = sys.version_info[0] >= 3
+ self.tmpdir = tempfile.mkdtemp(prefix='pycrc.')
+ self.check_file = None
+ self.crc_bin_bbb_c89 = None
+ self.crc_bin_bbb_c99 = None
+ self.crc_bin_bbf_c89 = None
+ self.crc_bin_bbf_c99 = None
+ self.crc_bin_bwe_c89 = None
+ self.crc_bin_bwe_c99 = None
+ self.crc_bin_tbl_c89 = None
+ self.crc_bin_tbl_c99 = None
+ self.crc_bin_tbl_sb4 = None
+ self.crc_bin_tbl_sb8 = None
+ self.crc_bin_tbl_sb16 = None
+ self.crc_bin_tbl_idx2 = None
+ self.crc_bin_tbl_idx4 = None
+
+ def __del__(self):
+ """
+ The class destructor. Delete all generated files.
+ """
+ if self.check_file is not None:
+ os.remove(self.check_file)
+ if self.crc_bin_bbb_c89 is not None:
+ self.__del_files([self.crc_bin_bbb_c89, self.crc_bin_bbb_c89+'.h', self.crc_bin_bbb_c89+'.c'])
+ if self.crc_bin_bbb_c99 is not None:
+ self.__del_files([self.crc_bin_bbb_c99, self.crc_bin_bbb_c99+'.h', self.crc_bin_bbb_c99+'.c'])
+ if self.crc_bin_bbf_c89 is not None:
+ self.__del_files([self.crc_bin_bbf_c89, self.crc_bin_bbf_c89+'.h', self.crc_bin_bbf_c89+'.c'])
+ if self.crc_bin_bbf_c99 is not None:
+ self.__del_files([self.crc_bin_bbf_c99, self.crc_bin_bbf_c99+'.h', self.crc_bin_bbf_c99+'.c'])
+ if self.crc_bin_bwe_c89 is not None:
+ self.__del_files([self.crc_bin_bwe_c89, self.crc_bin_bwe_c89+'.h', self.crc_bin_bwe_c89+'.c'])
+ if self.crc_bin_bwe_c99 is not None:
+ self.__del_files([self.crc_bin_bwe_c99, self.crc_bin_bwe_c99+'.h', self.crc_bin_bwe_c99+'.c'])
+ if self.crc_bin_tbl_c89 is not None:
+ self.__del_files([self.crc_bin_tbl_c89, self.crc_bin_tbl_c89+'.h', self.crc_bin_tbl_c89+'.c'])
+ if self.crc_bin_tbl_c99 is not None:
+ self.__del_files([self.crc_bin_tbl_c99, self.crc_bin_tbl_c99+'.h', self.crc_bin_tbl_c99+'.c'])
+ if self.crc_bin_tbl_sb4 is not None:
+ self.__del_files([self.crc_bin_tbl_sb4, self.crc_bin_tbl_sb4+'.h', self.crc_bin_tbl_sb4+'.c'])
+ if self.crc_bin_tbl_sb8 is not None:
+ self.__del_files([self.crc_bin_tbl_sb8, self.crc_bin_tbl_sb8+'.h', self.crc_bin_tbl_sb8+'.c'])
+ if self.crc_bin_tbl_sb16 is not None:
+ self.__del_files([self.crc_bin_tbl_sb16, self.crc_bin_tbl_sb16+'.h', self.crc_bin_tbl_sb16+'.c'])
+ if self.crc_bin_tbl_idx2 is not None:
+ self.__del_files([self.crc_bin_tbl_idx2, self.crc_bin_tbl_idx2+'.h', self.crc_bin_tbl_idx2+'.c'])
+ if self.crc_bin_tbl_idx4 is not None:
+ self.__del_files([self.crc_bin_tbl_idx4, self.crc_bin_tbl_idx4+'.h', self.crc_bin_tbl_idx4+'.c'])
+ os.removedirs(self.tmpdir)
+
+ def __del_files(delf, files):
+ """
+ Helper function to delete files.
+ """
+ for f in files:
+ try:
+ os.remove(f)
+ except:
+ print("error: can't delete {0:s}".format(f))
+ pass
+
+ def __get_status_output(self, cmd_str):
+ if self.python3:
+ import subprocess
+ return subprocess.getstatusoutput(cmd_str)
+ else:
+ import commands
+ return commands.getstatusoutput(cmd_str)
+
+ def __make_src(self, args, basename, cstd):
+ """
+ Generate the *.h and *.c source files for a test.
+ """
+ gen_src = '{0:s}/{1:s}'.format(self.tmpdir, basename)
+ cmd_str = self.pycrc_bin + ' {0:s} --std {1:s} --generate h -o {2:s}.h'.format(args, cstd, gen_src)
+ if self.verbose:
+ print(cmd_str)
+ ret = self.__get_status_output(cmd_str)
+ if ret[0] != 0:
+ print('error: the following command returned error: {0:s}'.format(cmd_str))
+ print(ret[1])
+ print(ret[2])
+ return None
+
+ cmd_str = self.pycrc_bin + ' {0:s} --std {1:s} --generate c-main -o {2:s}.c'.format(args, cstd, gen_src)
+ if self.verbose:
+ print(cmd_str)
+ ret = self.__get_status_output(cmd_str)
+ if ret[0] != 0:
+ print('error: the following command returned error: {0:s}'.format(cmd_str))
+ print(ret[1])
+ print(ret[2])
+ return None
+ return gen_src
+
+ def __compile(self, args, binfile, cstd):
+ """
+ Compile a generated source file.
+ """
+ cmd_str = 'gcc -W -Wall -pedantic -Werror -std={0:s} -o {1:s} {2:s}.c'.format(cstd, binfile, binfile)
+ if self.verbose:
+ print(cmd_str)
+ ret = self.__get_status_output(cmd_str)
+ if len(ret) > 1 and len(ret[1]) > 0:
+ print(ret[1])
+ if ret[0] != 0:
+ print('error: {0:d} with command error: {1:s}'.format(ret[0], cmd_str))
+ return None
+ return binfile
+
+ def __make_bin(self, args, basename, cstd='c99'):
+ """
+ Generate the source and compile to a binary.
+ """
+ filename = self.__make_src(args, basename, cstd)
+ if filename is None:
+ return None
+ if not self.__compile(args, filename, cstd):
+ self.__del_files([filename, filename+'.h', filename+'.c'])
+ return None
+ return filename
+
+ def __setup_files(self, opt):
+ """
+ Set up files needed during the test.
+ """
+ if self.verbose:
+ print('Setting up files...')
+ self.check_file = '{0:s}/check.txt'.format(self.tmpdir)
+ f = open(self.check_file, 'wb')
+ if self.python3:
+ f.write(bytes('123456789', 'utf-8'))
+ else:
+ f.write('123456789')
+ f.close()
+
+ if opt.Compile:
+ if self.use_algo_bit_by_bit:
+ filename = self.__make_bin('--algorithm bit-by-bit', 'crc_bbb_c89', 'c89')
+ if filename is None:
+ return False
+ self.crc_bin_bbb_c89 = filename
+
+ filename = self.__make_bin('--algorithm bit-by-bit', 'crc_bbb_c99', 'c99')
+ if filename is None:
+ return False
+ self.crc_bin_bbb_c99 = filename
+
+ if self.use_algo_bit_by_bit_fast:
+ filename = self.__make_bin('--algorithm bit-by-bit-fast', 'crc_bbf_c89', 'c89')
+ if filename is None:
+ return False
+ self.crc_bin_bbf_c89 = filename
+
+ filename = self.__make_bin('--algorithm bit-by-bit-fast', 'crc_bbf_c99', 'c99')
+ if filename is None:
+ return False
+ self.crc_bin_bbf_c99 = filename
+
+ if self.use_algo_table_driven:
+ filename = self.__make_bin('--algorithm table-driven', 'crc_tbl_c89', 'c89')
+ if filename is None:
+ return False
+ self.crc_bin_tbl_c89 = filename
+
+ filename = self.__make_bin('--algorithm table-driven', 'crc_tbl_c99', 'c99')
+ if filename is None:
+ return False
+ self.crc_bin_tbl_c99 = filename
+
+# FIXME don't test undefined params
+# filename = self.__make_bin('--algorithm table-driven --slice-by 4', 'crc_tbl_sb4')
+# if filename is None:
+# return False
+# self.crc_bin_tbl_sb4 = filename
+#
+# filename = self.__make_bin('--algorithm table-driven --slice-by 8', 'crc_tbl_sb8')
+# if filename is None:
+# return False
+# self.crc_bin_tbl_sb8 = filename
+#
+# filename = self.__make_bin('--algorithm table-driven --slice-by 16', 'crc_tbl_sb16')
+# if filename is None:
+# return False
+# self.crc_bin_tbl_sb16 = filename
+
+ filename = self.__make_bin('--algorithm table-driven --table-idx-width 2', 'crc_tbl_idx2')
+ if filename is None:
+ return False
+ self.crc_bin_tbl_idx2 = filename
+
+ filename = self.__make_bin('--algorithm table-driven --table-idx-width 4', 'crc_tbl_idx4')
+ if filename is None:
+ return False
+ self.crc_bin_tbl_idx4 = filename
+
+ return True
+
+
+ def __run_command(self, cmd_str):
+ """
+ Run a command and return its stdout.
+ """
+ if self.verbose:
+ print(cmd_str)
+ ret = self.__get_status_output(cmd_str)
+ if ret[0] != 0:
+ print('error: the following command returned error: {0:s}'.format(cmd_str))
+ print(ret[1])
+ return None
+ return ret[1]
+
+ def __check_command(self, cmd_str, expected_result):
+ """
+ Run a command and check if the stdout matches the expected result.
+ """
+ ret = self.__run_command(cmd_str)
+ if int(ret, 16) != expected_result:
+ print('error: different checksums!')
+ print('{0:s}: expected {1:#x}, got {2:s}'.format(cmd_str, expected_result, ret))
+ return False
+ return True
+
+ def __check_bin(self, args, expected_result, long_data_type = True):
+ """
+ Check all precompiled binaries.
+ """
+ for binary in [
+ self.crc_bin_bbb_c89, self.crc_bin_bbb_c99,
+ self.crc_bin_bbf_c89, self.crc_bin_bbf_c99,
+ self.crc_bin_tbl_c89, self.crc_bin_tbl_c99,
+ self.crc_bin_tbl_sb4, self.crc_bin_tbl_sb8, self.crc_bin_tbl_sb16,
+ self.crc_bin_tbl_idx2, self.crc_bin_tbl_idx4]:
+ if binary is not None:
+ # Don't test width > 32 for C89, as I don't know how to ask for an data type > 32 bits.
+ if binary[-3:] == 'c89' and long_data_type:
+ continue
+ cmd_str = binary + ' ' + args
+ if not self.__check_command(cmd_str, expected_result):
+ return False
+ return True
+
+ def __get_crc(self, model, check_str = '123456789', expected_crc = None):
+ """
+ Get the CRC for a set of parameters from the Python reference implementation.
+ """
+ if self.verbose:
+ out_str = 'Crc(width = {width:d}, poly = {poly:#x}, reflect_in = {reflect_in}, xor_in = {xor_in:#x}, reflect_out = {reflect_out}, xor_out = {xor_out:#x})'.format(**model)
+ if expected_crc is not None:
+ out_str += ' [check = {0:#x}]'.format(expected_crc)
+ print(out_str)
+ alg = Crc(width = model['width'], poly = model['poly'],
+ reflect_in = model['reflect_in'], xor_in = model['xor_in'],
+ reflect_out = model['reflect_out'], xor_out = model['xor_out'])
+ error = False
+ crc = expected_crc
+
+ if self.use_algo_bit_by_bit:
+ bbb_crc = alg.bit_by_bit(check_str)
+ if crc is None:
+ crc = bbb_crc
+ error = error or bbb_crc != crc
+ if self.use_algo_bit_by_bit_fast:
+ bbf_crc = alg.bit_by_bit_fast(check_str)
+ if crc is None:
+ crc = bbf_crc
+ error = error or bbf_crc != crc
+ if self.use_algo_table_driven:
+ tbl_crc = alg.table_driven(check_str)
+ if crc is None:
+ crc = tbl_crc
+ error = error or tbl_crc != crc
+
+ if error:
+ print('error: different checksums!')
+ if expected_crc is not None:
+ print(' check: {0:#x}'.format(expected_crc))
+ if self.use_algo_bit_by_bit:
+ print(' bit-by-bit: {0:#x}'.format(bbb_crc))
+ if self.use_algo_bit_by_bit_fast:
+ print(' bit-by-bit-fast: {0:#x}'.format(bbf_crc))
+ if self.use_algo_table_driven:
+ print(' table_driven: {0:#x}'.format(tbl_crc))
+ return None
+ return crc
+
+ def __compile_and_check_res(self, cmp_opt, run_opt, name, expected_crc):
+ """
+ Compile a model and run it.
+ """
+ filename = self.__make_bin(cmp_opt, name)
+ if filename is None:
+ return False
+ if run_opt is None:
+ cmd = filename
+ else:
+ cmd = filename + ' ' + run_opt
+ ret = self.__check_command(cmd, expected_crc)
+ self.__del_files([filename, filename+'.h', filename+'.c'])
+ if not ret:
+ return False
+ return True
+
+
+ def __test_models(self):
+ """
+ Standard Tests.
+ Test all known models.
+ """
+ if self.verbose:
+ print('Running __test_models()...')
+ check_str = '123456789'
+ check_bytes = bytearray(check_str, 'utf-8')
+ models = CrcModels()
+ for m in models.models:
+ expected_crc = m['check']
+ if self.__get_crc(m, check_str, expected_crc) != expected_crc:
+ return False
+
+ ext_args = '--width {width:d} --poly {poly:#x} --xor-in {xor_in:#x} --reflect-in {reflect_in} --xor-out {xor_out:#x} --reflect-out {reflect_out}'.format(**m)
+
+ cmd_str = '{0:s} --model {1:s}'.format(self.pycrc_bin, m['name'])
+ if not self.__check_command(cmd_str, expected_crc):
+ return False
+
+ cmd_str = '{0:s} {1:s}'.format(self.pycrc_bin, ext_args)
+ if not self.__check_command(cmd_str, expected_crc):
+ return False
+
+ cmd_str = '{0:s} {1:s} --check-hexstring {2:s}'.format(self.pycrc_bin, ext_args, ''.join(['{0:02x}'.format(c) for c in check_bytes]))
+ if not self.__check_command(cmd_str, expected_crc):
+ return False
+
+ cmd_str = '{0:s} --model {1:s} --check-file {2:s}'.format(self.pycrc_bin, m['name'], self.check_file)
+ if not self.__check_command(cmd_str, expected_crc):
+ return False
+
+ if not self.__check_bin(ext_args, expected_crc, m['width'] > 32):
+ return False
+
+ if self.verbose:
+ print("")
+ return True
+
+
+ def __test_compiled_models(self):
+ """
+ Standard Tests.
+ Test all known models with the compiled code
+ """
+ if self.verbose:
+ print('Running __test_compiled_models()...')
+ models = CrcModels()
+ for m in models.models:
+ expected_crc = m['check']
+ cmp_opt = '--model {name}'.format(**m)
+
+ if self.use_algo_bit_by_bit:
+ if not self.__compile_and_check_res('--algorithm bit-by-bit' + ' ' + cmp_opt, None, 'crc_bbb_mod', expected_crc):
+ return False
+
+ if self.use_algo_bit_by_bit_fast:
+ if not self.__compile_and_check_res('--algorithm bit-by-bit-fast' + ' ' + cmp_opt, None, 'crc_bbf_mod', expected_crc):
+ return False
+
+ if self.use_algo_table_driven:
+ if not self.__compile_and_check_res('--algorithm table-driven' + ' ' + cmp_opt, None, 'crc_tbl_mod', expected_crc):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm table-driven --slice-by=4' + ' ' + cmp_opt, None, 'crc_tsb4_mod', expected_crc):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm table-driven --slice-by=8' + ' ' + cmp_opt, None, 'crc_tsb8_mod', expected_crc):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm table-driven --slice-by=16' + ' ' + cmp_opt, None, 'crc_tsb16_mod', expected_crc):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm table-driven --table-idx-width=2' + ' ' + cmp_opt, None, 'crc_tix2_mod', expected_crc):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm table-driven --table-idx-width=4' + ' ' + cmp_opt, None, 'crc_tix4_mod', expected_crc):
+ return False
+ return True
+
+
+ def __test_compiled_special_cases(self):
+ """
+ Standard Tests.
+ Test some special cases.
+ """
+ if self.verbose:
+ print('Running __test_compiled_special_cases()...')
+ if self.use_algo_table_driven:
+ if not self.__compile_and_check_res('--model=crc-5 --reflect-in=0 --algorithm table-driven --table-idx-width=8', None, 'crc_tbl_special', 0x01):
+ return False
+ if not self.__compile_and_check_res('--model=crc-5 --reflect-in=0 --algorithm table-driven --table-idx-width=4', None, 'crc_tbl_special', 0x01):
+ return False
+ if not self.__compile_and_check_res('--model=crc-5 --reflect-in=0 --algorithm table-driven --table-idx-width=2', None, 'crc_tbl_special', 0x01):
+ return False
+ return True
+
+
+ def __test_variable_width(self):
+ """
+ Test variable width.
+ """
+ if self.verbose:
+ print('Running __test_variable_width()...')
+ models = CrcModels()
+ m = models.get_params('crc-64-jones')
+
+ for width in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 23, 24, 25, 31, 32, 33, 63, 64]:
+ mask = (1 << width) - 1
+ mw = {
+ 'width': width,
+ 'poly': m['poly'] & mask,
+ 'reflect_in': m['reflect_in'],
+ 'xor_in': m['xor_in'] & mask,
+ 'reflect_out': m['reflect_out'],
+ 'xor_out': m['xor_out'] & mask,
+ }
+ args = '--width {width:d} --poly {poly:#x} --xor-in {xor_in:#x} --reflect-in {reflect_in} --xor-out {xor_out:#x} --reflect-out {reflect_out}'.format(**mw)
+
+ check = self.__get_crc(mw)
+ if check is None:
+ return False
+
+ if self.use_algo_bit_by_bit:
+ if self.crc_bin_bbb_c99 is not None:
+ if not self.__check_command(self.crc_bin_bbb_c99 + ' ' + args, check):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm bit-by-bit' + ' ' + args, None, 'crc_bbb_arg', check):
+ return False
+
+ if self.use_algo_bit_by_bit_fast:
+ if self.crc_bin_bbf_c99 is not None:
+ if not self.__check_command(self.crc_bin_bbf_c99 + ' ' + args, check):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm bit-by-bit-fast' + ' ' + args, None, 'crc_bbf_arg', check):
+ return False
+
+ if self.use_algo_table_driven:
+ if self.crc_bin_tbl_c99 is not None:
+ if not self.__check_command(self.crc_bin_tbl_c99 + ' ' + args, check):
+ return False
+
+ if not self.__compile_and_check_res('--algorithm table-driven' + ' ' + args, None, 'crc_tbl_arg', check):
+ return False
+ return True
+
+
+ def __test_compiled_mixed_args(self):
+ """
+ Test compiled arguments.
+ """
+ if self.verbose:
+ print('Running __test_compiled_mixed_args()...')
+ m = {
+ 'name': 'zmodem',
+ 'width': ['', '--width 16'],
+ 'poly': ['', '--poly 0x1021'],
+ 'reflect_in': ['', '--reflect-in False'],
+ 'xor_in': ['', '--xor-in 0x0'],
+ 'reflect_out': ['', '--reflect-out False'],
+ 'xor_out': ['', '--xor-out 0x0'],
+ 'check': 0x31c3,
+ }
+ cmp_args = {}
+ run_args = {}
+ for b_width in range(2):
+ cmp_args['width'] = m['width'][b_width]
+ run_args['width'] = m['width'][1 - b_width]
+ for b_poly in range(2):
+ cmp_args['poly'] = m['poly'][b_poly]
+ run_args['poly'] = m['poly'][1 - b_poly]
+ for b_ref_in in range(2):
+ cmp_args['reflect_in'] = m['reflect_in'][b_ref_in]
+ run_args['reflect_in'] = m['reflect_in'][1 - b_ref_in]
+ for b_xor_in in range(2):
+ cmp_args['xor_in'] = m['xor_in'][b_xor_in]
+ run_args['xor_in'] = m['xor_in'][1 - b_xor_in]
+ for b_ref_out in range(2):
+ cmp_args['reflect_out'] = m['reflect_out'][b_ref_out]
+ run_args['reflect_out'] = m['reflect_out'][1 - b_ref_out]
+ for b_xor_out in range(2):
+ cmp_args['xor_out'] = m['xor_out'][b_xor_out]
+ run_args['xor_out'] = m['xor_out'][1 - b_xor_out]
+
+ cmp_opt = '{width:s} {poly:s} {reflect_in} {xor_in:s} {reflect_out} {xor_out:s}'.format(**cmp_args)
+ run_opt = '{width:s} {poly:s} {reflect_in} {xor_in:s} {reflect_out} {xor_out:s}'.format(**run_args)
+
+ if self.use_algo_bit_by_bit:
+ if not self.__compile_and_check_res('--algorithm bit-by-bit' + ' ' + cmp_opt, run_opt, 'crc_bbb_arg', m['check']):
+ return False
+
+ if self.use_algo_bit_by_bit_fast:
+ if not self.__compile_and_check_res('--algorithm bit-by-bit-fast' + ' ' + cmp_opt, run_opt, 'crc_bbf_arg', m['check']):
+ return False
+
+ if self.use_algo_table_driven:
+ if not self.__compile_and_check_res('--algorithm table-driven' + ' ' + cmp_opt, run_opt, 'crc_tbl_arg', m['check']):
+ return False
+ return True
+
+
+ def __test_random_params(self):
+ """
+ Test random parameters.
+ """
+ if self.verbose:
+ print('Running __test_random_params()...')
+ for width in [8, 16, 32]:
+ for poly in [0x8005, 0x4c11db7, 0xa5a5a5a5]:
+ poly = poly & ((1 << width) - 1)
+ for refin in [0, 1]:
+ for refout in [0, 1]:
+ for init in [0x0, 0x1, 0x5a5a5a5a]:
+ args='--width {0:d} --poly {1:#x} --reflect-in {2} --reflect-out {3} --xor-in {4:#x} --xor-out 0x0'.format(width, poly, refin, refout, init)
+ cmd_str = self.pycrc_bin + ' ' + args
+ ret = self.__run_command(cmd_str)
+ if ret is None:
+ return False
+ ret = int(ret, 16)
+ if not self.__check_bin(args, ret, width > 32):
+ return False
+ return True
+
+
+ def run(self, opt):
+ """
+ Run all tests
+ """
+ self.use_algo_bit_by_bit = 'bit-by-bit' in opt.algorithm or 'bbb' in opt.algorithm
+ self.use_algo_bit_by_bit_fast = 'bit-by-bit-fast' in opt.algorithm or 'bbf' in opt.algorithm
+ self.use_algo_table_driven = 'table-driven' in opt.algorithm or 'tbl' in opt.algorithm
+ self.verbose = opt.verbose
+
+ if self.python3:
+ self.pycrc_bin = 'python3 pycrc.py'
+ else:
+ self.pycrc_bin = 'python pycrc.py'
+
+ if not self.__setup_files(opt):
+ return False
+
+ if not self.__test_models():
+ return False
+
+ if opt.Compile and not self.__test_compiled_models():
+ return False
+
+ if opt.Compile and not self.__test_compiled_special_cases():
+ return False
+
+ if opt.VariableWidth and not self.__test_variable_width():
+ return False
+
+ if opt.CompileMixedArgs and not self.__test_compiled_mixed_args():
+ return False
+
+ if opt.RandomParameters and not self.__test_random_params():
+ return False
+
+ return True
+
+
+def main():
+ """
+ Main function.
+ """
+ opt = Options()
+ opt.parse(sys.argv[1:])
+
+ test = CrcTests()
+ if not test.run(opt):
+ return 1
+ print('Test OK')
+ return 0
+
+
+# program entry point
+if __name__ == '__main__':
+ sys.exit(main())