< 返回版块

苦瓜小仔 发表于 2021-05-30 15:51

bench! :

  1. 插入 #[bench] 测试代码,无需再手动引入 test::Bencher ,让单元测试里的函数名与被测试的函数 同名 。(最重要的目的是,我想让测试函数与被测试函数同名)
  2. 两种测试样式:封装成 assert_eq! 型;传入辅助测试函数(里面可测试多个断言)和被测试函数型。
  3. 为了避免同时使用两种测试样式造成同名冲突(或者与测试模块下其他函数重名),可选添加函数名前缀。

例子:

#[cfg(test)]
mod bench {
    fn string_from(s: &str) -> String { String::from(s) }
    bench!(string_from(""); target = ""; prefix = __); // 如果没有前缀,会与 string_from 重名冲突
    bench!(String::from(""); target = ""; prefix = __); // 如果没有前缀,会与 from 重名冲突

    fn assert<F>(f: F)
        where F: Fn(&'static str) -> String {
        assert_eq!(f(""), "");
    }
    bench!(assert string_from; prefix = ___); // 如果没有前缀,会与 string_from 重名冲突
    bench!(assert String::from); // 取 from 函数名
}
test _macros::bench::___string_from ... ok
test _macros::bench::__from ... ok
test _macros::bench::__string_from ... ok
test _macros::bench::from ... ok

vec_pos!

  1. 目的:打印数组和索引名称与位置。
  2. 索引名称与位置参数有两种样式:传入外部定义的变量名;传入 未定义的变量名 = 位置
  3. 同一个位置多个索引名称时,只打印第一个传入的名称。
  4. 索引名称长度超过打印的数组元素长度时,截断名称。
  5. 索引位置不必有序。

例子:

#[test]
fn pos() {
    let v = vec![1, 2, 3];
    assert_eq!(vec_pos!(v; i = 1, j = 2, k = 0), ["[1 2 3]", " 0 1 2 ", " k i j "]);
    assert_eq!(vec_pos!(v; i = 1, j = 1, k = 0), ["[1 2 3]", " 0 1   ", " k i   "]);
    let n = 1;
    assert_eq!(vec_pos!(v; n), ["[1 2 3]", "   1   ", "   n   "]);
    assert_eq!(vec_pos!(v; i = n, j = 1, k = 0), ["[1 2 3]", " 0 1   ", " k i   "]);

    let v = vec!["hello", "world", "!"];
    assert_eq!(vec_pos!(v; i = 1, j_trunc = 2, k = 0), ["[\"hello\" \"world\" \"!\"]",
                                                        " 0       1       2   ",
                                                        " k       i       j_tr"]);

    let v = vec![1.2, 0., -8.5];
    assert_eq!(vec_pos!(v; i = 1, j = 2, k = 0), ["[1.2 0.0 -8.5]",
                                                  " 0   1   2    ",
                                                  " k   i   j    "]);
}

定义的代码:

#[macro_export]
macro_rules! bench {
    () => {};

    ($func:ident($($args:expr),*); target = $target:expr $(; prefix = $prefix:ident)?) => {
        paste::paste! {
            #[bench]
            fn [<$($prefix)? $func>](b: &mut test::Bencher) {
                b.iter(|| { assert_eq!($func($($args),*), $target); })
            }
        }
    };
    ($solution:tt:: $func:ident($($args:expr),*); target = $target:expr $(; prefix = $prefix:ident)?) => {
        // ($solution:tt:: $func:ident($($args:expr),*); $(target = )? $target:expr) => {
        paste::paste! {
            #[bench]
            fn [<$($prefix)? $func>](b: &mut test::Bencher) {
                b.iter(|| { assert_eq!($solution::$func($($args),*), $target); })
            }
        }
    };

    ($assert:ident $func:ident $(; prefix = $prefix:ident)?) => {
        paste::paste! {
            #[bench]
            fn [<$($prefix)? $func>](b: &mut test::Bencher) { b.iter(|| { $assert($func); }) }
        }
    };
    ($assert:ident $solution:tt:: $func:ident $(; prefix = $prefix:ident)?) => {
        paste::paste! {
            #[bench]
            fn [<$($prefix)? $func>](b: &mut test::Bencher) { b.iter(|| { $assert($solution::$func); }) }
        }
    };
}


#[macro_export]
macro_rules! vec_pos {
    () => {};
    ($vec:expr; $($name:ident = $pos:expr),*) => {
        $crate::_macros::vec_pos(format!("{:?}", $vec), vec![$(stringify!($name)),*], vec![$($pos),*])
    };
    ($vec:expr; $($pos:expr),*) => {
        $crate::_macros::vec_pos(format!("{:?}", $vec), vec![$(stringify!($pos)),*], vec![$($pos),*])
    };
}

pub fn vec_pos(v_str: String, names: Vec<&str>, pos: Vec<usize>) -> [String; 3] {
    // 排序、去重
    let mut names_pos = names.into_iter().zip(pos).collect::<Vec<_>>();
    names_pos.sort_by_key(|(_a, b)| *b);
    names_pos.dedup_by_key(|(_a, b)| *b);
    let (names, pos): (Vec<_>, Vec<_>) = names_pos.into_iter().unzip();

    let [mut v_res, mut pos_res, mut name_res]: [String; 3] = Default::default();
    let mut name;
    for (i, v) in v_str.split(',').enumerate() {
        v_res = format!("{}{}", v_res, v);
        if let Ok(p) = pos.binary_search(&i) {
            pos_res = format!("{} {}{}", pos_res, i, " ".repeat(v.len() - i.to_string().len() - 1));
            name = names[p];
            name_res = if v.len() - 1 < name.len() {
                format!("{} {}", name_res, &name[..v.len() - 1])
            } else {
                format!("{} {}{}", name_res, name, " ".repeat(v.len() - name.len() - 1))
            };
        } else {
            pos_res = format!("{}{}", pos_res, " ".repeat(v.len()),);
            name_res = format!("{}{}", name_res, " ".repeat(v.len()));
        }
    }

    println!("{}\n{}\n{}", v_res, pos_res, name_res);
    [v_res, pos_res, name_res]
}

Ext Link: https://gitee.com/ZIP97/leetcode/blob/master/src/_macros.rs

评论区

写评论

还没有评论

1 共 0 条评论, 1 页