Add an FFI test facility

This allow testing Rust functions (from fish_tests.cpp) which need to
cross the FFI. See the example in smoke.rs.
This commit is contained in:
ridiculousfish 2023-01-15 14:56:04 -08:00
parent 096b254c4a
commit 681a165721
8 changed files with 114 additions and 0 deletions

View file

@ -17,6 +17,7 @@ set(fish_autocxx_gen_dir "${CMAKE_BINARY_DIR}/fish-autocxx-gen/")
corrosion_import_crate(
MANIFEST_PATH "${CMAKE_SOURCE_DIR}/fish-rust/Cargo.toml"
FEATURES "fish-ffi-tests"
)
# We need the build dir because cxx puts our headers in there.

32
fish-rust/Cargo.lock generated
View file

@ -232,6 +232,16 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "ctor"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "cxx"
version = "1.0.81"
@ -343,6 +353,7 @@ dependencies = [
"cxx-build",
"cxx-gen",
"errno",
"inventory",
"lazy_static",
"libc",
"miette",
@ -364,6 +375,17 @@ dependencies = [
"wasi",
]
[[package]]
name = "ghost"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41973d4c45f7a35af8753ba3457cc99d406d863941fd7f52663cff54a5ab99b3"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "gimli"
version = "0.27.0"
@ -432,6 +454,16 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "inventory"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16fe3b35d64bd1f72917f06425e7573a2f63f74f42c8f56e53ea6826dde3a2b5"
dependencies = [
"ctor",
"ghost",
]
[[package]]
name = "is_ci"
version = "1.1.1"

View file

@ -10,6 +10,7 @@ widestring-suffix = { path = "./widestring-suffix/" }
autocxx = "0.23.1"
cxx = "1.0"
errno = "0.2.8"
inventory = { version = "0.3.3", optional = true}
lazy_static = "1.4.0"
libc = "0.2.137"
nix = "0.25.0"
@ -26,6 +27,12 @@ miette = { version = "5", features = ["fancy"] }
[lib]
crate-type=["staticlib"]
[features]
# The fish-ffi-tests feature causes tests to be built which need to use the FFI.
# These tests are run by fish_tests().
default = ["fish-ffi-tests"]
fish-ffi-tests = ["inventory"]
[patch.crates-io]
cxx = { git = "https://github.com/ridiculousfish/cxx", branch = "fish" }
cxx-gen = { git = "https://github.com/ridiculousfish/cxx", branch = "fish" }

View file

@ -21,6 +21,7 @@ fn main() -> miette::Result<()> {
let source_files = vec![
"src/fd_readable_set.rs",
"src/ffi_init.rs",
"src/ffi_tests.rs",
"src/smoke.rs",
"src/topic_monitor.rs",
];

View file

@ -0,0 +1,63 @@
/// Support for tests which need to cross the FFI.
/// Because the C++ is not compiled by `cargo test` and there is no natural way to
/// do it, use the following facilities for tests which need to use C++ types.
/// This uses the inventory crate to build a custom-test harness
/// as described at https://www.infinyon.com/blog/2021/04/rust-custom-test-harness/
/// See smoke.rs add_test for an example of how to use this.
#[cfg(all(feature = "fish-ffi-tests", not(test)))]
mod ffi_tests_impl {
use inventory;
/// A test which needs to cross the FFI.
#[derive(Debug)]
pub struct FFITest {
pub name: &'static str,
pub func: fn(),
}
/// Add a new test.
/// Example usage:
/// ```
/// add_test!("test_name", || {
/// assert!(1 + 2 == 3);
/// });
/// ```
macro_rules! add_test {
($name:literal, $func:expr) => {
inventory::submit!(crate::ffi_tests::FFITest {
name: $name,
func: $func,
});
};
}
pub(crate) use add_test;
inventory::collect!(crate::ffi_tests::FFITest);
/// Runs all ffi tests.
pub fn run_ffi_tests() {
for test in inventory::iter::<crate::ffi_tests::FFITest> {
println!("Running ffi test {}", test.name);
(test.func)();
}
}
}
#[cfg(not(all(feature = "fish-ffi-tests", not(test))))]
mod ffi_tests_impl {
macro_rules! add_test {
($name:literal, $func:expr) => {};
}
pub(crate) use add_test;
pub fn run_ffi_tests() {}
}
pub(crate) use ffi_tests_impl::*;
#[cxx::bridge(namespace = rust)]
mod ffi_tests {
extern "Rust" {
fn run_ffi_tests();
}
}

View file

@ -10,6 +10,7 @@ mod fd_readable_set;
mod fds;
mod ffi;
mod ffi_init;
mod ffi_tests;
mod flog;
mod signal;
mod smoke;

View file

@ -19,3 +19,8 @@ mod tests {
assert_eq!(result, 4);
}
}
use crate::ffi_tests::add_test;
add_test!("test_add", || {
assert_eq!(add(2, 3), 5);
});

View file

@ -63,6 +63,7 @@
#include "fd_readable_set.rs.h"
#include "fds.h"
#include "ffi_init.rs.h"
#include "ffi_tests.rs.h"
#include "function.h"
#include "future_feature_flags.h"
#include "global_safety.h"
@ -7148,6 +7149,8 @@ void test_rust_smoke() {
do_test(x == 42);
}
void test_rust_ffi() { rust::run_ffi_tests(); }
// typedef void (test_entry_point_t)();
using test_entry_point_t = void (*)();
struct test_t {
@ -7269,6 +7272,7 @@ static const test_t s_tests[]{
{TEST_GROUP("re"), test_re_substitute},
{TEST_GROUP("wgetopt"), test_wgetopt},
{TEST_GROUP("rust_smoke"), test_rust_smoke},
{TEST_GROUP("rust_ffi"), test_rust_ffi},
};
void list_tests() {