Testing strategy
Unit tests
Normally one writes Rust unit tests with functions marked with the
#[test]
attribute. This makes cargo test
create little programs
with the test functions.
However, gnome-class is not a normal library. It defines a procedural macro that runs at compilation time of the user's program. We need to create tests that are run at compilation time.
To do this, we have a second procedural macro called testme!()
.
It gets called from tests/lib-unit-tests.rs
as a normal procedural
macro. The macro implementation, in src/lib.rs
, calls
functions from the various modules in gnome-class. These functions
work like normal unit tests.
Adding a new unit test
Create a test function in one of the files under src/
, and make sure
that it ultimately gets called by testme()
in src/lib.rs
. Your
test will run as part of the tests/lib-unit-tests
program.
Unfortunately we cannot run individual unit tests with this scheme;
all the tests must be run in a single shot.
Integration tests
Our integration tests consist of full invocations of the
gobject_gen!
macro; they live in the tests/
directory.
Things to test for:
-
Can the resulting GObjects be instantiated?
-
Do internal fields get dropped when an object is finalized?
-
Can one call methods? Do they come with the correct arguments and argument types?
-
Can one override virtual methods?
-
Can signals be connected and emitted? Do they have the correct arguments?
-
Can properties be read/written? Do they have the correct argument types?
-
Can we declare interfaces? Can we implement classes with those interfaces?
-
Can we inherit from an existing class? Can we implement an existing interface?
-
Do class/interface structs have the correct size?
-
Does the generated C-callable API work?
Mixed tests
Mixed tests are meant to test the integration between rust objects and c-code. It is a subset of the integration tests and consist of three part:
- The rust code (defined in
tests/testname.rs
) - The c code (defined in
mixed_tests/testname.c
) - Glue crate (
mixed_tests/Cargo.toml
with crate-namegobject_gen_test
) - generated code by gobject_gen (
mixed_tests/rustgen/testname.rs
).
Rust code
The rust code is the place where the unit-test begins. It contains rust-defined gobjects and ways to test it. Furthermore, it can contains call to c-code (not related to gobject). Those methods are responsible to execute the c-parts of the test.
C-code
This code is responsible for running the c-side of the test. It can check if it can create a type defined in the rust-part, it can try if it can use a type defined in rust or it can try to subclass a type implemented in rust. It can also check if the generated header-file fulfills its needs.
Glue-crate
The crate gobject-gen-test
, defined in mixed_tests
is used to contain the c-functions.
It is build all the c-code files in build.rs
. The compiled crate exposed the
entry-points of the c-code. It is linked only the tests-crate and not to the main crates.
That keeps the test-c-code out of the final shared object.
Generated code
To use a rust-defined gobject in c, its needs a basic definition defined in a header file.
That definition will only be available after the procedural macro is run, which is too
late for our case. To these files pre-exists in mixed-tests/rustgen
.
The rust-side of the unittest can compare the pre-existing header file with the
header file it would generate, and fail the test if those files do not match.
Compatibility
The mixed tests current depends on pkg-config
, so I don't think it works on Windows.