繁体   English   中英

如何在 #![no_std] env 中测试 core::fmt::Display trait 实现的结果

[英]How to test result of core::fmt::Display trait implementation in #![no_std] env

我有以下结构并想测试 Display trait 的实现:

use core::fmt::{Display, Formatter, Result};

struct B {}

impl Display for B {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(f, "A {} C", "B")
    }
}

#[test]
fn it_works() {
    assert_eq!(format!("{}", B {}), "A B C")
}

它在一般情况下有效,但是在#![no_std]环境中,由于format! 缺少宏(它分配,因此不能在no_std中使用)。

no_std场景中是否有惯用的方法来测试core::std::Display特征? 我尝试使用自定义缓冲区实现创建自己的core::std::Formatter实例以某种方式规避它,并直接测试fmt方法,但实例化这种类型被认为是编译器内部的。

为什么不在自定义缓冲区上实现core::fmt::Write并使用core::fmt::write! 给它?

format! 基本上是write! 到一个字符串缓冲区,两者都真正调用Write::write_fmtformat! 具有它提供自己的(字符串)缓冲区并在错误时发生恐慌的便利。

macro_rules! write {
    ($dst:expr, $($arg:tt)*) => {
        $dst.write_fmt($crate::format_args!($($arg)*))
    };
}
macro_rules! format {
    ($($arg:tt)*) => {{
        let res = $crate::fmt::format($crate::__export::format_args!($($arg)*));
        res
    }}
}
pub fn format(args: Arguments<'_>) -> string::String {
    let capacity = args.estimated_capacity();
    let mut output = string::String::with_capacity(capacity);
    output.write_fmt(args).expect("a formatting trait implementation returned an error");
    output
}

最好的选择是为测试启用标准:

#![cfg_attr(no_std, not(test))]

如果你做不到,并且你知道格式大小的上限,你可以为一个u8数组包装器实现core::fmt::Write并使用它。 arrayvec已经为您提供了ArrayString

let mut formatted = ArrayString::<10>::new();
use core::fmt::Write;
write!(formatted, "{}", B {}).expect("failed to format, probably buffer too small");
assert_eq!(&formatted, "A B C")

游乐场

正如@Masklinn 所提到的,只需实现core::fmt::Write特征,就可以在没有分配和任何缓冲区的情况下做到这一点。

这是示例实现:

#![no_std]
use core::fmt::{Display, Formatter, Result, Write};

struct B {}

impl Display for B {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(f, "A {} C", "B")
    }
}

struct Comparator<'a> {
    valid: bool,
    to_compare: &'a str
}

impl<'a> Comparator<'a> {
    fn new(s: &'a str) -> Self {
        Self { valid: true, to_compare: s }
    }

    fn is_valid(self) -> bool {
        self.valid && self.to_compare.is_empty()
    }
}


impl<'a> Write for Comparator<'a> {
    fn write_str(&mut self, s: &str) -> Result {
        if s.eq(self.to_compare) {
            self.valid = self.valid && true;
            self.to_compare = "";
            return Ok(());
        }

        if self.to_compare.starts_with(s) && self.to_compare.len() >= s.len() {
            self.to_compare = &self.to_compare[s.len()..];
        } else {
            self.valid = false
        }
        Ok(())
    }
}

#[test]
fn it_works() {
    let mut cmp = Comparator::new("A B C");
    let _ = write!(&mut cmp, "{}", B{});
    assert!(cmp.is_valid());
}

#[test]
fn too_short() {
    let mut cmp = Comparator::new("A B");
    let _ = write!(&mut cmp, "{}", B{});
    assert!(!cmp.is_valid());
}

#[test]
fn too_long() {
    let mut cmp = Comparator::new("A B C D");
    let _ = write!(&mut cmp, "{}", B{});
    assert!(!cmp.is_valid());
}

编辑:修复了代码中的错误,是:

 if self.to_compare.starts_with(s) && self.to_compare.len() >= s.len() {
            self.to_compare = &self.to_compare[s.len()..];
            self.valid = true
        } else {
            self.valid = false
        }

固定的:

 if self.to_compare.starts_with(s) && self.to_compare.len() >= s.len() {
            self.to_compare = &self.to_compare[s.len()..];
        } else {
            self.valid = false
        }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM