cxx icon indicating copy to clipboard operation
cxx copied to clipboard

Adding C++ Code in Rust cxx bridge unit tests

Open harmic opened this issue 4 years ago • 3 comments

I am writing some Rust code that will interface with existing C++, and I am trying to write unit tests for it. The C++ tests will require some test C++ functions (that will not be needed in normal operation) so I want them only to be compiled in when running the tests.

Here is a mock up of what I am trying to achieve:

#[cxx::bridge]
mod ffi {
	unsafe extern "C++" {
		include!("src/foo.h");

		type Foo;

		pub fn greet(&self);
	}
}

#[cfg(test)]
mod tests {

	#[cxx::bridge]
	mod ffi {
		unsafe extern "C++" {
			include!("src/test.h");

			fn make_foo() -> UniquePtr<Foo>;
		}
	}

	#[test]
	fn test_foo() {
		let foo = unsafe { ffi::make_foo() };
		foo.greet();
	}
}

That leads to the error:

error: unsupported type: Foo
  --> src/lib.rs:23:31
   |
23 |             fn make_foo() -> UniquePtr<Foo>;
   |                                        ^^^

OK, so I guess I need to make use of the feature Safely unifying occurrences of an extern type across bridges described in the documentation, so I add this to my test cxx bridge:

			type Foo = super::ffi::Foo;

Now it is complaining about this:

  error[cxxbridge]: the name `Foo` is defined multiple times
     ┌─ src/lib.rs:21:4
     │
  21 │             type Foo = super::ffi::Foo;
     │             ^^^^^^^^ the name `Foo` is defined multiple times

But that Foo is in a different Rust module to the first one, so this shouldn't be a collision?

Is it a rule that a type can only be defined once in each source file regardless of the Rust namespaces that they occur in? Also what is the best practice for testing such bridges?

harmic avatar Jul 08 '21 23:07 harmic

I've partially worked around this by making my tests integration tests instead of unit tests (arguably they should have been integration tests from the start). This means the "test" cxx bridge is in a different file and I don't get the multiple definition error.

But that opens up another problem: I need to have the build.rs compile the second file as well, but only when doing a 'cargo test' not when doing a regular build. And I can't find a way from inside the build.rs to detect that it is building the integration test.

harmic avatar Jul 09 '21 02:07 harmic

And I can't find a way from inside the build.rs to detect that it is building the integration test.

Can't you test for the test cfg? https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts

auscompgeek avatar Jul 17 '21 06:07 auscompgeek

I got it to dump it's entire environment, and the only CARGO_CFG_xxx variables there were the ones listed on that page, relating to the target. There was no CARGO_CFG_TEST.

harmic avatar Jul 17 '21 07:07 harmic