Testing framework for the Game Boy Advance.
Using gba_test
requires a nightly
Rust version.
- ARM Binutils: At minimum, you'll need the ARM GNU linker (
arm-none-eabi-ld
) to properly build projects usinggba_test
. You can obtain it from the ARM website. - rust-src - GBA development requires
build-std
to work. Runrustup component add rust-src
to enable it. cargo
configuration - Configuration forcargo
should be provided in acargo/config.toml
file within your project. An example configuration is as follows:
[build]
target = "thumbv4t-none-eabi"
[target.thumbv4t-none-eabi]
runner = "mgba"
rustflags = ["-Clinker=arm-none-eabi-ld", "-Clink-arg=-Tgba.ld", "-Ztrap-unreachable=no"]
[unstable]
build-std = ["alloc", "core"]
In your Cargo.toml
manifest, add gba_test
to your list of dev-dependencies:
[package]
name = "your_project"
version = "0.1.0"
edition = "2021"
[dev-dependencies]
gba_test = "0.3.0"
gba_test
provides its own test runner. To run the tests, you'll need to call the runner from your main()
function.
The following code can be used to call the test runner when you run cargo test
:
#![no_std]
#![cfg_attr(test, no_main)]
#![cfg_attr(test, feature(custom_test_frameworks))]
#![cfg_attr(test, test_runner(gba_test::runner))]
#![cfg_attr(test, reexport_test_harness_main = "test_harness")]
#[cfg(test)]
#[no_mangle]
pub fn main() {
test_harness()
}
Calling test_harness()
will run all tests defined within your project.
gba_test
provides its own custom #[test]
attribute for defining tests. It works similar to the default #[test]
attribute.
// A very simple function to test.
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)]
mod tests {
use super::add;
use gba_test::test;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
Other common testing attributes are also supported, including #[ignore]
and #[should_panic]
.
gba_test
can be run on anything that runs .gba
files, ranging from original Game Boy Advance hardware to emulators.
For development workflows, it is recommended to run tests on an emulator. The example cargo/config.toml
provided in the "Prerequisites" section will enable you to run tests on mGBA (assuming mgba
is in your PATH) when you run cargo test
.
To run on real Game Boy Advance hardware, you can flash the generated test binary to a cartridge.
When running cargo test
, a .elf
test binary is generated. Emulators like mGBA can run this .elf
file, but real hardware requires a .gba
file. The location of your test binary is output by cargo test
. For example, running cargo test
on the gba_test
library itself outputs something like:
Running unittests src\lib.rs (target\thumbv4t-none-eabi\debug\deps\gba_test-5b5cf1bdf24b2915)
The path in the parenthesis is the location of the test binary. You can use arm-none-eabi-objcopy
(obtained from the ARM website) to create a .gba
file from this binary:
arm-none-eabi-objcopy -O binary target\thumbv4t-none-eabi\debug\deps\gba_test-5b5cf1bdf24b2915 test.gba
Next, run gbafix
:
cargo install gbafix
gbafix test.gba
Now, test.gba
is prepared to run on real Game Boy Advance hardware. See documentation for your flash cart for instructions on flashing the .gba
file to the cartridge and running it.
gba_test
is configured to be run with the mgba-rom-test
binary using SWI call 0x27
with r0
as the output register. The following exit values may be emitted:
0
- A successful test run.1
- One or more tests failed.2
- The tests failed to complete. This indicates that a panic occurred outside of test execution.
To use mgba-rom-test
in continuous integration with GitHub Actions, it is recommended to use the github-mgba-rom-test
action. See this project's GitHub Actions setup for examples of this workflow.
Some emulators, such as mGBA or no$gba, support logging. gba_test
provides optional integration with the log
crate to log information about test running. You can enable logging through the log feature:
[dev-dependencies]
gba_test = {version = "0.1.4", features = ["log"]}
You can also log within your tests using the log
crate:
use gba_test::test;
#[test]
fn foo() {
log::info!("important information");
}
To produce the log output for your emulator, you'll need to use a logger implementation specific for that emulator's logging interface. The following logger implementations are recommended:
- mGBA:
mgba_log
- no$gba:
nocash_gba_log
Initialize the logger prior to calling the test runner, like so:
#![no_std]
#![cfg_attr(test, no_main)]
#![cfg_attr(test, feature(custom_test_frameworks))]
#![cfg_attr(test, test_runner(gba_test::runner))]
#![cfg_attr(test, reexport_test_harness_main = "test_harness")]
#[cfg(test)]
#[no_mangle]
pub fn main() {
mgba_log::init();
test_harness()
}
This project is licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.