如何为私有模块编写文档测试

3
我正在使用Rust编写一个库,该库公开了一个使用私有模块的函数。现在,我可以使用以下命令呈现此私有模块的文档: cargo doc --document-private-items 现在,我有一个名为reader的模块,其中包含一些函数的结构体。该模块本身使用mod readerlib.rs文件中导入,并具有一个类型,类似于:use reader:: BufferedOpenTypeFontReader; 现在,我想向BufferedOpenTypeFontReader结构添加一些文档,这是它的实现:
    /// A buffered `&[u8]` reader for reading an OpenType Font (OTF).
    pub struct BufferedOpenTypeFontReader<'a> {
        reader: BufReader<&'a [u8]>,
    }

    //# The basic implementation of the `OpenTypeFontByteSliceReader` struct.
    impl<'a> BufferedOpenTypeFontReader<'a> {
        //# Defines the constants which are required in this `impl` block.
        const U32_SIZE: usize = 4; // The amount of bytes in a `u32`.

        /// Create a new `BufferedOpenTypeFontReader<'a>` implementation which reads from the given `&[u8]`.
        ///
        /// # Examples:
        ///  ```
        /// use otfdecode::reader::BufferedOpenTypeFontReader;
        ///
        /// let otf_bytes = [];
        /// let otf_reader = BufferedOpenTypeFontReader::new(otf_bytes);
        ///  ```
        pub fn new(data: &'a [u8]) -> Self {
            Self {
                reader: BufReader::new(data),
            }
        }

        pub fn read_u32(&mut self) -> u32 {
            let mut buffer = [0u8; Self::U32_SIZE];
            self.reader.read_exact(&mut buffer).unwrap();

            u32::from_be_bytes(buffer)
        }
    }

然而,当我运行cargo test时,我遇到了以下问题:
failures:

---- src\reader.rs - reader::BufferedOpenTypeFontReader::new (line 42) stdout ----
error[E0603]: module `reader` is private
  --> src\reader.rs:43:16
   |
4  | use otfdecode::reader::BufferedOpenTypeFontReader;
   |                ^^^^^^ private module
   |
note: the module `reader` is defined here
  --> C:\Users\kevin\Development\github.com\kdeconinck\OTFDecode\app\src\lib.rs:30:1
   |
30 | mod reader;
   |

我怎样才能为函数new编写文档测试而不使模块reader公开?
2个回答

2

在撰写本文时,Rust 尚不支持此功能。我对此问题进行了一些研究,并得出以下结论:

为什么这是个问题

Doctest 被编译为单独的外部单元。首先编译您的库,然后将 doctest 编译单元链接到您的库上。当编译 doctest 时,库的行为与外部库完全相同。甚至 pub(crate) 也无法使用,因为根据编译器的说法,它确实是一个单独的库。

如果您将文档视为帮助人们使用您的库的产品,则这在哲学上是有道理的。他们将像使用外部库一样使用您的库,因此使库的行为与他们所期望的一样是有意义的。但这种做法的缺点是,它会有点阻碍为其他目的编写(好的)文档:使库本身更易于长期维护。

有些人想要改变这种情况。特别是,请参见 this issue。但截至本文撰写时,它还没有得到很多关注。

解决方法

实际上没有好的解决方法。这些是人们想出来的解决方法,但都不令人满意:

  • 简单地不编写使用私有符号的文档测试。而是使用单元测试。然而,这通常会使您的文档变得更糟。
  • 在使用私有符号的doctest中添加ignore。这样做的缺点是,如果以后进行更改,则无法确定文档示例是否仍然有效(除非将代码复制到单元测试中,但那样就会有重复的代码)。像这样:
/// Computes the sum of two numbers.
///
/// # Examples
/// ```ignore
/// use calculator::adder::private_adder;
/// assert_eq!(5, private_adder(2, 3));
/// ```
fn private_adder(left: i32, right: i32) { left + right }
  • 将您的符号全部公开,但在detailprivate子模块下“隐藏”,以便库的用户清楚地知道它不应该被使用。这种方法的缺点是它仍然允许库的用户发现和使用这些函数,认为他们很聪明,然后可能破坏东西。它还会使您的公共API变得混乱,并可能揭示更多关于库内部机密业务逻辑的信息,如果这是您所担心的。
  • 有一个叫做Visibility的crate,它允许您根据功能更改符号的可见性。使用它,您可以在启用功能时使每个私有符号都变为公共的。然后,通过向命令添加doctest_privates功能,可以编译您的doctests:cargo test --doc --features doctest_privates。但是,这需要将以下属性添加到您的每个私有符号(或者至少是您想在doctest中使用的所有模块、类和函数):
/// Computes the sum of two numbers.
///
/// # Examples
/// ```
/// use calculator::adder::private_adder;
/// assert_eq!(5, private_adder(2, 3));
/// ```
#[cfg_attr(feature = "document_privates", visibility::make(pub))]
fn private_adder(left: i32, right: i32) { left + right }

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接