Skip to content

Commit d2936f9

Browse files
authored
Add support for doctests (#52)
1 parent 4e16502 commit d2936f9

File tree

8 files changed

+145
-24
lines changed

8 files changed

+145
-24
lines changed

azure-pipelines.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ jobs:
191191
workingDirectory: example-kernels/runner
192192
displayName: 'Run `cargo xrun` for "runner" kernel'
193193
194+
- script: cargo xtest -Z doctest-xcompile
195+
workingDirectory: example-kernels/runner-doctest
196+
displayName: 'Run `cargo xtest -Z doctest-xcompile` for "runner-doctest" kernel'
197+
194198
- script: cargo xtest
195199
workingDirectory: example-kernels/runner-test
196200
displayName: 'Run `cargo xtest` for "runner-test" kernel'

example-kernels/Cargo.lock

Lines changed: 23 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example-kernels/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ members = [
44
"default-target-bootimage",
55
"default-target-cargo",
66
"runner",
7+
"runner-doctest",
78
"runner-test",
89
"testing-qemu-exit-code",
910
"testing-serial-result",
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[build]
2+
target = "../x86_64-bootimage-example-kernels.json"
3+
4+
[target.'cfg(target_os = "none")']
5+
runner = "bootimage runner"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target/
2+
**/*.rs.bk
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "runner-doctest"
3+
version = "0.1.0"
4+
authors = ["Philipp Oppermann <[email protected]>"]
5+
edition = "2018"
6+
7+
[dependencies]
8+
bootloader = "0.6.4"
9+
x86_64 = "0.5.3"
10+
11+
[package.metadata.bootimage]
12+
test-success-exit-code = 33 # (0x10 << 1) | 1
13+
test-args = ["-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-display", "none"]
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#![no_std]
2+
#![cfg_attr(test, no_main)]
3+
#![feature(custom_test_frameworks)]
4+
#![test_runner(crate::test_runner)]
5+
#![reexport_test_harness_main = "test_main"]
6+
7+
/// add two numbers
8+
///
9+
/// ```
10+
/// #![no_std]
11+
/// #![no_main]
12+
/// use runner_doctest::{add, exit_qemu, ExitCode};
13+
/// #[export_name = "_start"]
14+
/// extern "C" fn start() {
15+
/// assert_eq!(add(1, 2), 3);
16+
/// unsafe { exit_qemu(ExitCode::Success); }
17+
/// }
18+
/// ```
19+
pub fn add(a: u32, b: u32) -> u32 {
20+
a + b
21+
}
22+
23+
/// multiply two numbers
24+
///
25+
/// ```
26+
/// #![no_std]
27+
/// #![no_main]
28+
/// use runner_doctest::{mul, exit_qemu, ExitCode};
29+
/// #[export_name = "_start"]
30+
/// extern "C" fn start() {
31+
/// assert_eq!(mul(2, 3), 6);
32+
/// unsafe { exit_qemu(ExitCode::Success); }
33+
/// }
34+
/// ```
35+
pub fn mul(a: u32, b: u32) -> u32 {
36+
a * b
37+
}
38+
39+
#[cfg(test)]
40+
fn test_runner(tests: &[&dyn Fn()]) {
41+
for test in tests.iter() {
42+
test();
43+
}
44+
45+
unsafe {
46+
exit_qemu(ExitCode::Success);
47+
}
48+
}
49+
50+
pub enum ExitCode {
51+
Success,
52+
Failed,
53+
}
54+
55+
impl ExitCode {
56+
fn code(&self) -> u32 {
57+
match self {
58+
ExitCode::Success => 0x10,
59+
ExitCode::Failed => 0x11,
60+
}
61+
}
62+
}
63+
64+
/// exit QEMU (see https://os.phil-opp.com/integration-tests/#shutting-down-qemu)
65+
pub unsafe fn exit_qemu(exit_code: ExitCode) {
66+
use x86_64::instructions::port::Port;
67+
68+
let mut port = Port::<u32>::new(0xf4);
69+
port.write(exit_code.code());
70+
}
71+
72+
#[cfg(test)]
73+
#[no_mangle]
74+
pub extern "C" fn _start() -> ! {
75+
test_main();
76+
77+
unsafe {
78+
exit_qemu(ExitCode::Failed);
79+
}
80+
81+
loop {}
82+
}
83+
84+
#[panic_handler]
85+
fn panic(_info: &core::panic::PanicInfo) -> ! {
86+
unsafe {
87+
exit_qemu(ExitCode::Failed);
88+
}
89+
loop {}
90+
}

src/subcommand/runner.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@ pub(crate) fn runner(args: RunnerArgs) -> Result<i32, ErrorMessage> {
99
.executable
1010
.parent()
1111
.ok_or("kernel executable has no parent")?;
12-
let is_test = exe_parent.ends_with("deps");
12+
let is_doctest = exe_parent
13+
.file_name()
14+
.ok_or("kernel executable's parent has no file name")?
15+
.to_str()
16+
.ok_or("kernel executable's parent file name is not valid UTF-8")?
17+
.starts_with("rustdoctest");
18+
let is_test = is_doctest || exe_parent.ends_with("deps");
1319

1420
let bootimage_bin = {
1521
let file_stem = args

0 commit comments

Comments
 (0)