Merge pull request #38 from dtolnay/suite

Add test suite covering various permutations of signatures
This commit is contained in:
David Tolnay 2020-02-22 23:03:10 -08:00 committed by GitHub
commit d1010bdb39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 372 additions and 2 deletions

View File

@ -29,8 +29,9 @@ thiserror = "1.0"
cc = "1.0.49"
[dev-dependencies]
cxx-test-suite = { version = "0", path = "tests/ffi" }
rustversion = "1.0"
trybuild = "1.0"
trybuild = "1.0.21"
[workspace]
members = ["cmd", "demo-rs", "macro"]
members = ["cmd", "demo-rs", "macro", "tests/ffi"]

14
tests/ffi/Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "cxx-test-suite"
version = "0.0.0"
edition = "2018"
publish = false
[lib]
path = "lib.rs"
[dependencies]
cxx = { path = "../.." }
[build-dependencies]
cxx = { path = "../.." }

11
tests/ffi/build.rs Normal file
View File

@ -0,0 +1,11 @@
fn main() {
if cfg!(trybuild) {
return;
}
cxx::Build::new()
.bridge("lib.rs")
.file("tests.cc")
.flag("-std=c++11")
.compile("cxx-test-suite");
}

115
tests/ffi/lib.rs Normal file
View File

@ -0,0 +1,115 @@
use cxx::{CxxString, UniquePtr};
#[cxx::bridge(namespace = tests)]
pub mod ffi {
struct Shared {
z: usize,
}
extern "C" {
include!("tests/ffi/tests.h");
type C;
fn c_return_primitive() -> usize;
fn c_return_shared() -> Shared;
//TODO fn c_return_box() -> Box<R>;
fn c_return_unique_ptr() -> UniquePtr<C>;
fn c_return_ref(shared: &Shared) -> &usize;
fn c_return_str(shared: &Shared) -> &str;
fn c_return_rust_string() -> String;
fn c_return_unique_ptr_string() -> UniquePtr<CxxString>;
fn c_take_primitive(n: usize);
fn c_take_shared(shared: Shared);
fn c_take_box(r: Box<R>);
fn c_take_unique_ptr(c: UniquePtr<C>);
//TODO fn c_take_ref_r(r: &R);
fn c_take_ref_c(c: &C);
fn c_take_str(s: &str);
fn c_take_rust_string(s: String);
fn c_take_unique_ptr_string(s: UniquePtr<CxxString>);
}
extern "Rust" {
type R;
fn r_return_primitive() -> usize;
fn r_return_shared() -> Shared;
//TODO fn r_return_box() -> Box<R>;
//TODO fn r_return_unique_ptr() -> UniquePtr<C>;
fn r_return_ref(shared: &Shared) -> &usize;
fn r_return_str(shared: &Shared) -> &str;
fn r_return_rust_string() -> String;
//TODO fn r_return_unique_ptr_string() -> UniquePtr<CxxString>;
fn r_take_primitive(n: usize);
fn r_take_shared(shared: Shared);
fn r_take_box(r: Box<R>);
fn r_take_unique_ptr(c: UniquePtr<C>);
fn r_take_ref_r(r: &R);
fn r_take_ref_c(c: &C);
fn r_take_str(s: &str);
fn r_take_rust_string(s: String);
fn r_take_unique_ptr_string(s: UniquePtr<CxxString>);
}
}
type R = ();
fn r_return_primitive() -> usize {
2020
}
fn r_return_shared() -> ffi::Shared {
ffi::Shared { z: 2020 }
}
fn r_return_ref(shared: &ffi::Shared) -> &usize {
&shared.z
}
fn r_return_str(shared: &ffi::Shared) -> &str {
let _ = shared;
"2020"
}
fn r_return_rust_string() -> String {
"2020".to_owned()
}
fn r_take_primitive(n: usize) {
assert_eq!(n, 2020);
}
fn r_take_shared(shared: ffi::Shared) {
assert_eq!(shared.z, 2020);
}
fn r_take_box(r: Box<R>) {
let _ = r;
}
fn r_take_unique_ptr(c: UniquePtr<ffi::C>) {
let _ = c;
}
fn r_take_ref_r(r: &R) {
let _ = r;
}
fn r_take_ref_c(c: &ffi::C) {
let _ = c;
}
fn r_take_str(s: &str) {
assert_eq!(s, "2020");
}
fn r_take_rust_string(s: String) {
assert_eq!(s, "2020");
}
fn r_take_unique_ptr_string(s: UniquePtr<CxxString>) {
assert_eq!(s.as_ref().unwrap().to_str().unwrap(), "2020");
}

111
tests/ffi/tests.cc Normal file
View File

@ -0,0 +1,111 @@
#include "tests/ffi/tests.h"
#include "tests/ffi/lib.rs"
extern "C" void cxx_test_suite_set_correct();
namespace tests {
C::C(size_t n) : n(n) {}
size_t C::get() const { return this->n; }
size_t c_return_primitive() { return 2020; }
Shared c_return_shared() { return Shared{2020}; }
std::unique_ptr<C> c_return_unique_ptr() {
return std::unique_ptr<C>(new C{2020});
}
const size_t &c_return_ref(const Shared &shared) { return shared.z; }
cxxbridge::RustStr c_return_str(const Shared &shared) {
(void)shared;
return "2020";
}
cxxbridge::RustString c_return_rust_string() { return "2020"; }
std::unique_ptr<std::string> c_return_unique_ptr_string() {
return std::unique_ptr<std::string>(new std::string("2020"));
}
void c_take_primitive(size_t n) {
if (n == 2020) {
cxx_test_suite_set_correct();
}
}
void c_take_shared(Shared shared) {
if (shared.z == 2020) {
cxx_test_suite_set_correct();
}
}
void c_take_box(cxxbridge::RustBox<R> r) {
(void)r;
cxx_test_suite_set_correct();
}
void c_take_unique_ptr(std::unique_ptr<C> c) {
if (c->get() == 2020) {
cxx_test_suite_set_correct();
}
}
void c_take_ref_r(const R &r) { (void)r; }
void c_take_ref_c(const C &c) {
if (c.get() == 2020) {
cxx_test_suite_set_correct();
}
}
void c_take_str(cxxbridge::RustStr s) {
if (std::string(s) == "2020") {
cxx_test_suite_set_correct();
}
}
void c_take_rust_string(cxxbridge::RustString s) {
if (std::string(s) == "2020") {
cxx_test_suite_set_correct();
}
}
void c_take_unique_ptr_string(std::unique_ptr<std::string> s) {
if (*s == "2020") {
cxx_test_suite_set_correct();
}
}
extern "C" const char *cxx_run_test() noexcept {
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define ASSERT(x) \
do { \
if (!(x)) { \
return "Assertion failed: `" #x "`, " __FILE__ ":" TOSTRING(__LINE__); \
} \
} while (false)
ASSERT(r_return_primitive() == 2020);
ASSERT(r_return_shared().z == 2020);
ASSERT(r_return_ref(Shared{2020}) == 2020);
ASSERT(std::string(r_return_str(Shared{2020})) == "2020");
ASSERT(std::string(r_return_rust_string()) == "2020");
r_take_primitive(2020);
r_take_shared(Shared{2020});
r_take_unique_ptr(std::unique_ptr<C>(new C{2020}));
r_take_ref_c(C{2020});
r_take_str(cxxbridge::RustStr("2020"));
// TODO r_take_rust_string(cxxbridge::RustString("2020"));
r_take_unique_ptr_string(
std::unique_ptr<std::string>(new std::string("2020")));
cxx_test_suite_set_correct();
return nullptr;
}
} // namespace tests

39
tests/ffi/tests.h Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include "include/cxxbridge.h"
#include <memory>
#include <string>
namespace tests {
struct R;
struct Shared;
class C {
public:
C(size_t n);
size_t get() const;
private:
size_t n;
};
size_t c_return_primitive();
Shared c_return_shared();
cxxbridge::RustBox<R> c_return_box();
std::unique_ptr<C> c_return_unique_ptr();
const size_t &c_return_ref(const Shared &shared);
cxxbridge::RustStr c_return_str(const Shared &shared);
cxxbridge::RustString c_return_rust_string();
std::unique_ptr<std::string> c_return_unique_ptr_string();
void c_take_primitive(size_t n);
void c_take_shared(Shared shared);
void c_take_box(cxxbridge::RustBox<R> r);
void c_take_unique_ptr(std::unique_ptr<C> c);
void c_take_ref_r(const R &r);
void c_take_ref_c(const C &c);
void c_take_str(cxxbridge::RustStr s);
void c_take_rust_string(cxxbridge::RustString s);
void c_take_unique_ptr_string(std::unique_ptr<std::string> s);
} // namespace tests

71
tests/test.rs Normal file
View File

@ -0,0 +1,71 @@
use cxx_test_suite::ffi;
use std::cell::Cell;
use std::ffi::CStr;
thread_local! {
static CORRECT: Cell<bool> = Cell::new(false);
}
#[no_mangle]
extern "C" fn cxx_test_suite_set_correct() {
CORRECT.with(|correct| correct.set(true));
}
macro_rules! check {
($run:expr) => {{
CORRECT.with(|correct| correct.set(false));
$run;
assert!(CORRECT.with(|correct| correct.get()), stringify!($run));
}};
}
#[test]
fn test_c_return() {
let shared = ffi::Shared { z: 2020 };
assert_eq!(2020, ffi::c_return_primitive());
assert_eq!(2020, ffi::c_return_shared().z);
ffi::c_return_unique_ptr();
assert_eq!(2020, *ffi::c_return_ref(&shared));
assert_eq!("2020", ffi::c_return_str(&shared));
assert_eq!("2020", ffi::c_return_rust_string());
assert_eq!(
"2020",
ffi::c_return_unique_ptr_string()
.as_ref()
.unwrap()
.to_str()
.unwrap()
);
}
#[test]
fn test_c_take() {
let unique_ptr = ffi::c_return_unique_ptr();
check!(ffi::c_take_primitive(2020));
check!(ffi::c_take_shared(ffi::Shared { z: 2020 }));
check!(ffi::c_take_box(Box::new(())));
check!(ffi::c_take_ref_c(unique_ptr.as_ref().unwrap()));
check!(ffi::c_take_unique_ptr(unique_ptr));
check!(ffi::c_take_str("2020"));
check!(ffi::c_take_rust_string("2020".to_owned()));
check!(ffi::c_take_unique_ptr_string(
ffi::c_return_unique_ptr_string()
));
}
#[test]
fn test_c_call_r() {
fn cxx_run_test() {
extern "C" {
fn cxx_run_test() -> *const i8;
}
let failure = unsafe { cxx_run_test() };
if !failure.is_null() {
let msg = unsafe { CStr::from_ptr(failure) };
eprintln!("{}", msg.to_string_lossy());
}
}
check!(cxx_run_test());
}

8
third-party/Cargo.lock generated vendored
View File

@ -81,6 +81,7 @@ dependencies = [
"cc",
"codespan",
"codespan-reporting",
"cxx-test-suite",
"cxxbridge-macro",
"link-cplusplus",
"proc-macro2",
@ -91,6 +92,13 @@ dependencies = [
"trybuild",
]
[[package]]
name = "cxx-test-suite"
version = "0.0.0"
dependencies = [
"cxx",
]
[[package]]
name = "cxxbridge-cmd"
version = "0.1.2"