io: Introduce api test file
Introduce an `io/tests/api.rs` file to test the API surface of the `io` crate. In doing so fix C-DEBUG and prove C-DEBUG-NONEMPTY. C-DEBUG: https://rust-lang.github.io/api-guidelines/debuggability.html#c-debug
This commit is contained in:
parent
01f3eefc12
commit
1175faca32
|
@ -5,6 +5,7 @@ use internals::rust_version;
|
|||
|
||||
/// A bridging wrapper providing the IO traits for types that already implement `std` IO traits.
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct FromStd<T>(T);
|
||||
|
||||
impl<T> FromStd<T> {
|
||||
|
@ -116,6 +117,7 @@ impl<T: std::io::Write> std::io::Write for FromStd<T> {
|
|||
|
||||
/// A bridging wrapper providing the std traits for types that already implement our traits.
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug)]
|
||||
pub struct ToStd<T>(T);
|
||||
|
||||
impl<T> ToStd<T> {
|
||||
|
|
|
@ -94,6 +94,7 @@ pub trait BufRead: Read {
|
|||
/// Reader adapter which limits the bytes read from an underlying reader.
|
||||
///
|
||||
/// Created by calling `[Read::take]`.
|
||||
#[derive(Debug)]
|
||||
pub struct Take<'a, R: Read + ?Sized> {
|
||||
reader: &'a mut R,
|
||||
remaining: u64,
|
||||
|
@ -191,6 +192,7 @@ impl BufRead for &[u8] {
|
|||
}
|
||||
|
||||
/// Wraps an in memory reader providing the `position` function.
|
||||
#[derive(Debug)]
|
||||
pub struct Cursor<T> {
|
||||
inner: T,
|
||||
pos: u64,
|
||||
|
@ -329,6 +331,7 @@ impl Write for &mut [u8] {
|
|||
/// A sink to which all writes succeed. See [`std::io::Sink`] for more info.
|
||||
///
|
||||
/// Created using `io::sink()`.
|
||||
#[derive(Debug)]
|
||||
pub struct Sink;
|
||||
|
||||
impl Write for Sink {
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
//! Test the API surface of `io`.
|
||||
//!
|
||||
//! The point of these tests are to check the API surface as opposed to test the API functionality.
|
||||
//!
|
||||
//! ref: <https://rust-lang.github.io/api-guidelines/about.html>
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use core::cell::Cell;
|
||||
use core::convert::Infallible;
|
||||
|
||||
// These imports test "typical" usage by user code.
|
||||
use bitcoin_io::{self as io, BufRead, Cursor, ErrorKind, Read, Sink, Take, Write};
|
||||
#[cfg(feature = "std")]
|
||||
use bitcoin_io::{FromStd, ToStd};
|
||||
|
||||
/// An arbitrary error kind.
|
||||
const ERROR_KIND: ErrorKind = ErrorKind::TimedOut;
|
||||
|
||||
/// A struct that includes all public non-error enums.
|
||||
#[derive(Debug)] // All public types implement Debug (C-DEBUG).
|
||||
struct Enums {
|
||||
a: ErrorKind,
|
||||
}
|
||||
|
||||
impl Enums {
|
||||
/// Creates an arbitrary `Enums` instance.
|
||||
fn new() -> Self { Self { a: ERROR_KIND } }
|
||||
}
|
||||
|
||||
/// A struct that includes all public non-error structs except `Take`.
|
||||
#[derive(Debug)] // All public types implement Debug (C-DEBUG).
|
||||
struct Structs {
|
||||
#[cfg(feature = "std")]
|
||||
a: FromStd<u32>,
|
||||
#[cfg(feature = "std")]
|
||||
b: ToStd<Dummy>,
|
||||
c: Cursor<Dummy>,
|
||||
d: Sink,
|
||||
}
|
||||
|
||||
impl Structs {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
#[cfg(feature = "std")]
|
||||
a: FromStd::new(0),
|
||||
#[cfg(feature = "std")]
|
||||
b: ToStd::new(DUMMY),
|
||||
c: Cursor::new(DUMMY),
|
||||
d: Sink,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)] // `Take` implements Debug (C-DEBUG).
|
||||
struct Taker<'a> {
|
||||
a: Take<'a, Dummy>,
|
||||
}
|
||||
|
||||
/// An arbitrary `Dummy` instance.
|
||||
static DUMMY: Dummy = Dummy(0);
|
||||
|
||||
/// Dummy struct to implement all the traits we provide.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct Dummy(u64);
|
||||
|
||||
impl Read for Dummy {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
|
||||
if buf.is_empty() {
|
||||
Ok(0)
|
||||
} else {
|
||||
buf[0] = (self.0 & 0xFF) as u8;
|
||||
Ok(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BufRead for Dummy {
|
||||
fn fill_buf(&mut self) -> Result<&[u8], io::Error> { Ok(&[]) }
|
||||
fn consume(&mut self, _: usize) {}
|
||||
}
|
||||
|
||||
impl Write for Dummy {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> { Ok(buf.len()) }
|
||||
fn write_all(&mut self, _: &[u8]) -> Result<(), io::Error> { Ok(()) }
|
||||
fn flush(&mut self) -> Result<(), io::Error> { Ok(()) }
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Dummy {
|
||||
fn as_ref(&self) -> &[u8] { &[] }
|
||||
}
|
||||
|
||||
/// A struct that includes all public non-error types.
|
||||
#[derive(Debug)] // All public types implement Debug (C-DEBUG).
|
||||
struct Types {
|
||||
a: Enums,
|
||||
b: Structs,
|
||||
}
|
||||
|
||||
impl Types {
|
||||
fn new() -> Self { Self { a: Enums::new(), b: Structs::new() } }
|
||||
}
|
||||
|
||||
/// A struct that includes all public error types.
|
||||
#[derive(Debug)] // `io::Error` only implements `Debug`.
|
||||
struct Errors {
|
||||
a: io::Error,
|
||||
}
|
||||
|
||||
// `Debug` representation is never empty (C-DEBUG-NONEMPTY).
|
||||
#[test]
|
||||
fn api_all_non_error_types_have_non_empty_debug() {
|
||||
let t = Types::new();
|
||||
|
||||
let debug = format!("{:?}", t.a.a);
|
||||
assert!(!debug.is_empty());
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
let debug = format!("{:?}", t.b.a);
|
||||
assert!(!debug.is_empty());
|
||||
let debug = format!("{:?}", t.b.b);
|
||||
assert!(!debug.is_empty());
|
||||
}
|
||||
let debug = format!("{:?}", t.b.c);
|
||||
assert!(!debug.is_empty());
|
||||
let debug = format!("{:?}", t.b.d);
|
||||
assert!(!debug.is_empty());
|
||||
}
|
||||
|
||||
// Types are `Send` and `Sync` where possible (C-SEND-SYNC).
|
||||
#[test]
|
||||
fn all_non_error_tyes_implement_send_sync() {
|
||||
fn assert_send<T: Send>() {}
|
||||
assert_send::<Types>();
|
||||
|
||||
fn assert_sync<T: Sync>() {}
|
||||
assert_sync::<Types>();
|
||||
}
|
Loading…
Reference in New Issue