ckb-fixed-hash-core 1.1.2

Provide several fixed-length binary data, aka fixed-sized hashes
Documentation
use crate::{H160, H256, H512, H520, error::FromStrError};
use std::str::FromStr;

macro_rules! test_from_trimmed_str_one_byte {
    ($name:ident, $trimmed_str:expr, $index:expr, $value:expr) => {
        let result = $name::from_trimmed_str($trimmed_str).unwrap();
        let mut expected = $name::default();
        expected.0[$index] = $value;
        assert_eq!(result, expected);
    };
}

#[test]
fn from_trimmed_str() {
    test_from_trimmed_str_one_byte!(H160, "1", 19, 1);
    test_from_trimmed_str_one_byte!(H256, "1", 31, 1);
    test_from_trimmed_str_one_byte!(H512, "1", 63, 1);
    test_from_trimmed_str_one_byte!(H520, "1", 64, 1);
    test_from_trimmed_str_one_byte!(H160, "10", 19, 16);
    test_from_trimmed_str_one_byte!(H256, "10", 31, 16);
    test_from_trimmed_str_one_byte!(H512, "10", 63, 16);
    test_from_trimmed_str_one_byte!(H520, "10", 64, 16);
    test_from_trimmed_str_one_byte!(H160, "100", 18, 1);
    test_from_trimmed_str_one_byte!(H256, "100", 30, 1);
    test_from_trimmed_str_one_byte!(H512, "100", 62, 1);
    test_from_trimmed_str_one_byte!(H520, "100", 63, 1);
}

macro_rules! test_from_str_via_trimmed_str {
    ($name:ident, $trimmed_str:expr, $full_str:expr) => {
        let expected = $name::from_trimmed_str($trimmed_str).unwrap();
        let result = $name::from_str($full_str).unwrap();
        assert_eq!(result, expected);
    };
}

#[test]
fn from_str() {
    {
        let full_str = "0000000000000000000000000000000000000001";
        test_from_str_via_trimmed_str!(H160, "1", full_str);
    }
    {
        let full_str = "0000000000000000000000000000000000000000000000000000000000000001";
        test_from_str_via_trimmed_str!(H256, "1", full_str);
    }
    {
        let full_str = "0000000000000000000000000000000000000000000000000000000000000000\
                        0000000000000000000000000000000000000000000000000000000000000001";
        test_from_str_via_trimmed_str!(H512, "1", full_str);
    }
    {
        let full_str = "0000000000000000000000000000000000000000000000000000000000000000\
                        0000000000000000000000000000000000000000000000000000000000000000\
                        01";
        test_from_str_via_trimmed_str!(H520, "1", full_str);
    }
    {
        let full_str = "1000000000000000000000000000000000000001";
        test_from_str_via_trimmed_str!(H160, full_str, full_str);
    }
    {
        let full_str = "1000000000000000000000000000000000000000000000000000000000000001";
        test_from_str_via_trimmed_str!(H256, full_str, full_str);
    }
    {
        let full_str = "1000000000000000000000000000000000000000000000000000000000000000\
                        0000000000000000000000000000000000000000000000000000000000000001";
        test_from_str_via_trimmed_str!(H512, full_str, full_str);
    }
    {
        let full_str = "1000000000000000000000000000000000000000000000000000000000000000\
                        0000000000000000000000000000000000000000000000000000000000000000\
                        01";
        test_from_str_via_trimmed_str!(H520, full_str, full_str);
    }
}

macro_rules! add_tests {
    ($test_name:ident, $type:ident, $bytes_size:literal) => {
        #[test]
        fn $test_name() {
            let zeros = $type([0; $bytes_size]);
            let zeros_str = format!("{:0>width$}", 0, width = $bytes_size * 2);
            let short_str = format!("{:0>width$}", 0, width = $bytes_size * 2 - 1);
            let long_str = format!("{:0>width$}", 0, width = $bytes_size * 2 + 1);
            let has_invalid_char_str = format!("x{:0>width$}", 0, width = $bytes_size * 2 - 1);
            {
                let from_zeros = $type::from_str(&zeros_str).unwrap();
                assert_eq!(zeros, from_zeros);
            }
            {
                let expected = FromStrError::InvalidLength(1);
                let actual = $type::from_str("0").unwrap_err();
                assert_eq!(expected, actual);

                let expected = FromStrError::InvalidLength($bytes_size * 2 - 1);
                let actual = $type::from_str(&short_str).unwrap_err();
                assert_eq!(expected, actual);

                let expected = FromStrError::InvalidLength($bytes_size * 2 + 1);
                let actual = $type::from_str(&long_str).unwrap_err();
                assert_eq!(expected, actual);

                let expected = FromStrError::InvalidCharacter { chr: b'x', idx: 0 };
                let actual = $type::from_str(&has_invalid_char_str).unwrap_err();
                assert_eq!(expected, actual);
            }
            {
                let from_empty = $type::from_trimmed_str("0").unwrap();
                assert_eq!(zeros, from_empty);

                let from_zero = $type::from_trimmed_str("").unwrap();
                assert_eq!(zeros, from_zero);
            }
            {
                let expected = FromStrError::InvalidLength($bytes_size * 2 + 1);
                let actual = $type::from_trimmed_str(&long_str).unwrap_err();
                assert_eq!(expected, actual);

                let expected = FromStrError::InvalidCharacter { chr: b'0', idx: 0 };
                let actual = $type::from_trimmed_str(&short_str).unwrap_err();
                assert_eq!(expected, actual);

                let expected = FromStrError::InvalidCharacter { chr: b'_', idx: 8 };
                let actual = $type::from_trimmed_str("12345678_90abcdef").unwrap_err();
                assert_eq!(expected, actual);
            }
            {
                let only_lowest_bit_is_one_str =
                    format!("{:0>width$}{}", 0, 0b0001, width = $bytes_size * 2 - 1);
                let from_full = $type::from_str(&only_lowest_bit_is_one_str).unwrap();
                let from_trimmed = $type::from_trimmed_str("1").unwrap();
                assert_eq!(from_full, from_trimmed);
            }
            {
                let only_highest_bit_is_one_str =
                    format!("{}{:0>width$}", 0b1000, 0, width = $bytes_size * 2 - 1);
                let from_full = $type::from_str(&only_highest_bit_is_one_str).unwrap();
                let from_trimmed = $type::from_trimmed_str(&only_highest_bit_is_one_str).unwrap();
                assert_eq!(from_full, from_trimmed);
            }
        }
    };
}

add_tests!(test_h160, H160, 20);
add_tests!(test_h256, H256, 32);
add_tests!(test_h512, H512, 64);
add_tests!(test_h520, H520, 65);