encoding-next_index_tests 0.1.5

Helper macros used to test index tables for character encodings
Documentation
// This is a part of encoding-next.
// Copyright (c) 2013-2015, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

//! Macros and utilities for testing indices.

/// Makes a common test suite for single-byte indices.
#[macro_export]
macro_rules! single_byte_tests {
    () => {
        mod tests {
            extern crate test;
            use super::{backward, forward};

            #[test]
            fn test_correct_table() {
                for i in 0x80..0x100 {
                    let i = i as u8;
                    let j = forward(i);
                    if j != 0xffff {
                        assert_eq!(backward(j as u32), i);
                    }
                }
                for i in 0..0x110000 {
                    let j = backward(i);
                    if j != 0 {
                        assert_eq!(forward(j) as u32, i);
                    }
                }
            }

            #[bench]
            fn bench_forward_sequential_128(bencher: &mut test::Bencher) {
                bencher.iter(|| {
                    for i in 0x80..0x100 {
                        test::black_box(forward(i as u8));
                    }
                })
            }

            // strongly prefers the performance for invalid characters
            #[bench]
            fn bench_backward_sequential_128(bencher: &mut test::Bencher) {
                let mut start: u32 = 0;
                bencher.iter(|| {
                    for i in start..(start + 0x80) {
                        test::black_box(backward(i));
                    }
                    start += 0x80;
                })
            }

            // strongly prefers the performance for valid characters
            #[bench]
            fn bench_roundtrip_sequential_128(bencher: &mut test::Bencher) {
                bencher.iter(|| {
                    for i in 0x80..0x100 {
                        let j = forward(i as u8);
                        if j != 0 {
                            test::black_box(backward(j as u32));
                        }
                    }
                })
            }
        }
    };
}

/// Makes a common test suite for multi-byte indices.
#[macro_export]
macro_rules! multi_byte_tests {
    (@shared dups=[$($dups:pat),* $(,)*]) => ( // internal macro
        fn in_dups(i: u16) -> bool {
            match i { $($dups => true,)* _ => false }
        }

        #[test]
        fn test_correct_table() {
            for i in 0..0x10000 {
                let i = i as u16;
                if in_dups(i) { continue; }
                let j = forward(i);
                if j != 0xffff { assert_eq!(backward(j), i); }
            }
            for i in 0..0x110000 {
                let j = backward(i);
                if in_dups(j) { continue; }
                if j != 0xffff { assert_eq!(forward(j), i); }
            }
        }

        #[bench]
        fn bench_forward_sequential_128(bencher: &mut test::Bencher) {
            let mut start: u32 = 0;
            bencher.iter(|| {
                for i in start..(start + 0x80) {
                    test::black_box(forward(i as u16));
                }
                start += 0x80;
            })
        }

        #[bench]
        fn bench_backward_sequential_128(bencher: &mut test::Bencher) {
            let mut start: u32 = 0;
            bencher.iter(|| {
                for i in start..(start + 0x80) {
                    test::black_box(backward(i));
                }
                start += 0x80;
                if start >= 0x110000 { start = 0; }
            })
        }
    );

    (
        dups = [$($dups:pat),* $(,)*]
    ) => (
        mod tests {
            extern crate test;
            use super::{forward, backward};

            $crate::multi_byte_tests!(@shared dups=[$($dups),*]);
        }
    );

    (
        remap = [$remap_min:expr, $remap_max:expr],
        dups = [$($dups:pat),* $(,)*]
    ) => (
        mod tests {
            extern crate test;
            use super::{forward, backward, backward_remapped};

            $crate::multi_byte_tests!(@shared dups=[$($dups),*]);

            static REMAP_MIN: u16 = $remap_min;
            static REMAP_MAX: u16 = $remap_max;

            #[test]
            fn test_correct_remapping() {
                for i in REMAP_MIN..(REMAP_MAX+1) {
                    let j = forward(i);
                    if j != 0xffff {
                        let ii = backward_remapped(j);
                        assert!(ii != i && ii != 0xffff);
                        let jj = forward(ii);
                        assert_eq!(j, jj);
                    }
                }
            }

            #[bench]
            fn bench_backward_remapped_sequential_128(bencher: &mut test::Bencher) {
                let mut start: u32 = 0;
                bencher.iter(|| {
                    for i in start..(start + 0x80) {
                        test::black_box(backward_remapped(i));
                    }
                    start += 0x80;
                    if start >= 0x110000 { start = 0; }
                })
            }
        }
    );
}

/// Makes a common test suite for multi-byte range indices.
#[macro_export]
macro_rules! multi_byte_range_tests {
    (
        key = [$minkey:expr, $maxkey:expr], key < $keyubound:expr,
        value = [$minvalue:expr, $maxvalue:expr], value < $valueubound:expr
    ) => {
        mod tests {
            extern crate test;
            use super::{backward, forward};

            static MIN_KEY: u32 = $minkey;
            static MAX_KEY: u32 = $maxkey;
            static KEY_UBOUND: u32 = $keyubound;
            static MIN_VALUE: u32 = $minvalue;
            static MAX_VALUE: u32 = $maxvalue;
            static VALUE_UBOUND: u32 = $valueubound;

            #[test]
            #[allow(unused_comparisons)]
            fn test_no_failure() {
                for i in MIN_KEY.saturating_sub(1)..(MAX_KEY + 2) {
                    forward(i);
                }
                for j in MIN_VALUE.saturating_sub(1)..(MAX_VALUE + 2) {
                    backward(j);
                }
            }

            #[test]
            fn test_correct_table() {
                for i in MIN_KEY..(MAX_KEY + 2) {
                    let j = forward(i);
                    if j == 0xffffffff {
                        continue;
                    }
                    let i_ = backward(j);
                    if i_ == 0xffffffff {
                        continue;
                    }
                    assert!(
                        i_ == i,
                        "backward(forward({})) = backward({}) = {} != {}",
                        i,
                        j,
                        i_,
                        i
                    );
                }
            }

            #[bench]
            fn bench_forward_sequential_128(bencher: &mut test::Bencher) {
                let mut start: u32 = 0;
                bencher.iter(|| {
                    for i in start..(start + 0x80) {
                        test::black_box(forward(i));
                    }
                    start += 0x80;
                    if start >= KEY_UBOUND {
                        start = 0;
                    }
                })
            }

            #[bench]
            fn bench_backward_sequential_128(bencher: &mut test::Bencher) {
                let mut start: u32 = 0;
                bencher.iter(|| {
                    for i in start..(start + 0x80) {
                        test::black_box(backward(i));
                    }
                    start += 0x80;
                    if start >= VALUE_UBOUND {
                        start = 0;
                    }
                })
            }
        }
    };
}