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())