Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ci/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ esac

# garando_errors only compiles on `cfg(any(unix, windows))`
case "$target" in
*wasm*) cmd="$cmd --exclude ctest --exclude ctest-test"
*wasm*) cmd="$cmd --exclude ctest --exclude ctest-test --exclude ctest-next"
esac

# # FIXME(ctest): duplicate symbol errors for statics, e.g. T1_static_mut_u8, on Unix-
Expand Down
26 changes: 26 additions & 0 deletions ctest-next/src/generator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use std::path::Path;

use crate::{expand, Result};

/// A builder used to generate a test suite.
#[non_exhaustive]
pub struct TestGenerator {}

impl Default for TestGenerator {
fn default() -> Self {
Self::new()
}
}

impl TestGenerator {
/// Creates a new blank test generator.
pub fn new() -> Self {
Self {}
}

/// Generate all tests for the given crate and output the Rust side to a file.
pub fn generate<P: AsRef<Path>>(&self, crate_path: P, _output_file_path: P) -> Result<()> {
let _expanded = expand(crate_path)?;
Ok(())
}
}
33 changes: 19 additions & 14 deletions ctest-next/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
#![warn(missing_docs)]
#![warn(unreachable_pub)]

//! # ctest2 - an FFI binding validator
//!
//! This library is intended to be used as a build dependency in a separate
//! project from the main repo to generate tests which can be used to validate
//! FFI bindings in Rust against the headers from which they come from.

mod generator;
mod macro_expansion;

pub use generator::TestGenerator;
pub use macro_expansion::expand;

/// A possible error that can be encountered in our library.
pub type Error = Box<dyn std::error::Error>;
/// A type alias for `std::result::Result` that defaults to our error type.
pub type Result<T, E = Error> = std::result::Result<T, E>;
23 changes: 23 additions & 0 deletions ctest-next/src/macro_expansion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use std::{env, fs::canonicalize, path::Path, process::Command};

use crate::Result;

/// Use rustc to expand all macros and pretty print the crate into a single file.
pub fn expand<P: AsRef<Path>>(crate_path: P) -> Result<String> {
let rustc = env::var("RUSTC").unwrap_or_else(|_| String::from("rustc"));

let output = Command::new(rustc)
.env("RUSTC_BOOTSTRAP", "1")
.arg("-Zunpretty=expanded")
.arg(canonicalize(crate_path)?)
.output()?;

if !output.status.success() {
let error = std::str::from_utf8(&output.stderr)?;
return Err(error.into());
}

let expanded = std::str::from_utf8(&output.stdout)?.to_string();

Ok(expanded)
}
39 changes: 39 additions & 0 deletions ctest-next/tests/basic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use ctest_next::TestGenerator;

#[test]
fn test_entrypoint_hierarchy() {
let generator = TestGenerator::new();

generator
.generate("./tests/input/hierarchy/lib.rs", "hierarchy_out.rs")
.unwrap();
}

#[test]
fn test_entrypoint_simple() {
let generator = TestGenerator::new();

generator
.generate("./tests/input/simple.rs", "simple_out.rs")
.unwrap();
}

#[test]
fn test_entrypoint_macro() {
let generator = TestGenerator::new();

generator
.generate("./tests/input/macro.rs", "macro_out.rs")
.unwrap();
}

#[test]
fn test_entrypoint_invalid_syntax() {
let generator = TestGenerator::new();

let fails = generator
.generate("./tests/input/invalid_syntax.rs", "invalid_syntax_out.rs")
.is_err();

assert!(fails)
}
2 changes: 2 additions & 0 deletions ctest-next/tests/input/hierarchy/bar/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#[allow(non_camel_case_types)]
pub type in6_addr = u32;
10 changes: 10 additions & 0 deletions ctest-next/tests/input/hierarchy/foo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use crate::bar::in6_addr;
use std::os::raw::c_void;

pub const ON: bool = true;

unsafe extern "C" {
fn malloc(size: usize) -> *mut c_void;

static in6addr_any: in6_addr;
}
4 changes: 4 additions & 0 deletions ctest-next/tests/input/hierarchy/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//! Ensure that our crate is able to handle definitions spread across many files

mod bar;
mod foo;
9 changes: 9 additions & 0 deletions ctest-next/tests/input/invalid_syntax.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
struct Foo {
a: int,
b: u8;
}

unin Bar {
x: u8,
y: u8
}
12 changes: 12 additions & 0 deletions ctest-next/tests/input/macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
macro_rules! vector {
($name:ident, $ty:ty) => {
#[repr(C)]
struct $name {
x: $ty,
y: $ty,
}
};
}

vector!(VecU8, u8);
vector!(VecU16, u16);
15 changes: 15 additions & 0 deletions ctest-next/tests/input/simple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use std::os::raw::c_char;

pub type Byte = u8;

#[repr(C)]
pub struct Person {
name: *const c_char,
age: u8,
}

#[repr(C)]
pub union Word {
word: u16,
byte: [Byte; 2],
}
Loading