Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pull out bindgen-tests into its own crate #189

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,18 @@ jobs:
cargo 3ds test --no-run --test layout_test --all-features --package ctru-sys
cargo 3ds test --no-run --lib --all-features --package ctru-rs

- name: Run helper tests
run: cargo test --package bindgen-tests

- name: Run lib and integration tests
uses: rust3ds/test-runner/run-tests@v1
with:
args: --tests --all-features --workspace
args: --tests --all-features

- name: Build and run doc tests
uses: rust3ds/test-runner/run-tests@v1
with:
args: --doc --workspace
args: --doc

- name: Upload citra logs and capture videos
uses: actions/upload-artifact@v3
Expand Down
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
[workspace]
members = ["ctru-rs", "ctru-sys", "test-runner"]
default-members = ["ctru-rs", "ctru-sys"]
members = ["bindgen-tests", "ctru-rs", "ctru-sys", "test-runner"]
default-members = ["ctru-rs", "ctru-sys", "test-runner"]
resolver = "2"

[workspace.dependencies]
libc = { version = "0.2.153", default-features = false }
bindgen = "0.69.4"
shim-3ds = { git = "https://github.com/rust3ds/shim-3ds.git" }
pthread-3ds = { git = "https://github.com/rust3ds/pthread-3ds.git" }
test-runner = { git = "https://github.com/rust3ds/ctru-rs.git" }
Expand All @@ -15,6 +16,7 @@ test-runner = { git = "https://github.com/rust3ds/ctru-rs.git" }
test-runner = { path = "test-runner" }
ctru-rs = { path = "ctru-rs" }
ctru-sys = { path = "ctru-sys" }
bindgen-tests = { path = "bindgen-tests" }

# This was the previous git repo for test-runner
[patch."https://github.com/rust3ds/test-runner.git"]
Expand Down
21 changes: 21 additions & 0 deletions bindgen-tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "bindgen-tests"
version = "0.1.0"
edition = "2021"

[features]
default = []
generate = [
"dep:bindgen",
"dep:proc-macro2",
"dep:quote",
"dep:regex",
"dep:rust-format",
]

[dependencies]
bindgen = { workspace = true, features = ["experimental"], optional = true }
proc-macro2 = { version = "1.0.81", optional = true }
quote = { version = "1.0.36", optional = true }
regex = { version = "1.10.4", optional = true }
rust-format = { version = "0.3.4", features = ["token_stream"], optional = true }
91 changes: 91 additions & 0 deletions bindgen-tests/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#[cfg(feature = "generate")]
pub mod test_gen;
#[cfg(feature = "generate")]
pub use test_gen::*;

pub use std::mem::offset_of;

pub fn size_of_ret<T, U>(_f: impl Fn(U) -> T) -> usize {
::std::mem::size_of::<T>()
}

#[macro_export]
macro_rules! size_of {
($ty:ident::$field:ident) => {{
$crate::size_of_ret(|x: $ty| x.$field)
}};
($ty:ty) => {
::std::mem::size_of::<$ty>()
};
($expr:expr) => {
::std::mem::size_of_val(&$expr)
};
}

pub fn align_of_ret<T, U>(_f: impl Fn(U) -> T) -> usize {
::std::mem::align_of::<T>()
}

#[macro_export]
macro_rules! align_of {
($ty:ident::$field:ident) => {{
// This matches the semantics of C++ alignof when it is applied to a struct
// member. Packed structs may under-align fields, so we take the minimum
// of the align of the struct and the type of the field itself.
$crate::align_of_ret(|x: $ty| x.$field).min(align_of!($ty))
}};
($ty:ty) => {
::std::mem::align_of::<$ty>()
};
($expr:expr) => {
::std::mem::align_of_val(&$expr)
};
}

#[cfg(test)]
mod tests {
macro_rules! packed_struct {
($name:ident, $size:literal) => {
#[repr(C, packed($size))]
struct $name {
a: u8,
b: u16,
c: u32,
d: u64,
}
};
}

packed_struct!(PackedStruct1, 1);
packed_struct!(PackedStruct2, 2);
packed_struct!(PackedStruct4, 4);
packed_struct!(PackedStruct8, 8);

#[test]
fn align_of_matches_cpp() {
// Expected values are based on C++: https://godbolt.org/z/dPnP7nEse
assert_eq!(align_of!(PackedStruct1), 1);
assert_eq!(align_of!(PackedStruct1::a), 1);
assert_eq!(align_of!(PackedStruct1::b), 1);
assert_eq!(align_of!(PackedStruct1::c), 1);
assert_eq!(align_of!(PackedStruct1::d), 1);

assert_eq!(align_of!(PackedStruct2), 2);
assert_eq!(align_of!(PackedStruct2::a), 1);
assert_eq!(align_of!(PackedStruct2::b), 2);
assert_eq!(align_of!(PackedStruct2::c), 2);
assert_eq!(align_of!(PackedStruct2::d), 2);

assert_eq!(align_of!(PackedStruct4), 4);
assert_eq!(align_of!(PackedStruct4::a), 1);
assert_eq!(align_of!(PackedStruct4::b), 2);
assert_eq!(align_of!(PackedStruct4::c), 4);
assert_eq!(align_of!(PackedStruct4::d), 4);

assert_eq!(align_of!(PackedStruct8), 8);
assert_eq!(align_of!(PackedStruct8::a), 1);
assert_eq!(align_of!(PackedStruct8::b), 2);
assert_eq!(align_of!(PackedStruct8::c), 4);
assert_eq!(align_of!(PackedStruct8::d), 8);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,10 @@ impl LayoutTestGenerator {
}
}

let test_name = format_ident!("layout_test_{struct_name}");
quote! {
#[test]
fn #name() {
fn #test_name() {
#(#field_tests);*
}
}
Expand Down
13 changes: 4 additions & 9 deletions ctru-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ default = []
## Downstream users of `ctru-sys` shouldn't need to use this feature.
layout-tests = [
"dep:cpp_build",
"dep:proc-macro2",
"dep:quote",
"dep:regex",
"dep:rust-format",
"dep:bindgen-tests",
]

[[test]]
Expand All @@ -33,21 +30,19 @@ required-features = ["layout-tests"]
libc = { workspace = true }

[build-dependencies]
bindgen = { version = "0.69", features = ["experimental"] }
bindgen = { workspace = true, features = ["experimental"] }
bindgen-tests = { git = "https://github.com/rust3ds/ctru-rs.git", optional = true, features = ["generate"] }
cc = "1.0"
# Use git dependency so we can use https://github.com/mystor/rust-cpp/pull/111
cpp_build = { optional = true, git = "https://github.com/mystor/rust-cpp.git" }
doxygen-rs = "0.4.2"
itertools = "0.11.0"
proc-macro2 = { version = "1.0.81", optional = true }
quote = { version = "1.0.36", optional = true }
regex = { version = "1.10.4", optional = true }
rust-format = { version = "0.3.4", optional = true, features = ["token_stream"] }
which = "4.4.0"

[dev-dependencies]
shim-3ds = { workspace = true }
test-runner = { workspace = true }
bindgen-tests = { git = "https://github.com/rust3ds/ctru-rs.git" }
cpp = "0.5.9"

[package.metadata.docs.rs]
Expand Down
11 changes: 2 additions & 9 deletions ctru-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,6 @@ use std::error::Error;
use std::path::{Path, PathBuf};
use std::process::{Command, Output, Stdio};

// This allows us to have a directory layout of build/*.rs which is a little
// cleaner than having all the submodules as siblings to build.rs.
mod build {
#[cfg(feature = "layout-tests")]
pub mod test_gen;
}

#[derive(Debug)]
struct CustomCallbacks;

Expand Down Expand Up @@ -146,7 +139,7 @@ fn main() {
.parse_callbacks(Box::new(CustomCallbacks));

#[cfg(feature = "layout-tests")]
let (test_callbacks, test_generator) = build::test_gen::LayoutTestCallbacks::new();
let (test_callbacks, test_generator) = bindgen_tests::LayoutTestCallbacks::new();
#[cfg(feature = "layout-tests")]
let binding_builder = binding_builder.parse_callbacks(Box::new(test_callbacks));

Expand Down Expand Up @@ -275,7 +268,7 @@ fn track_libctru_files(pacman: &Path) -> Result<(), String> {
#[cfg(feature = "layout-tests")]
fn generate_layout_tests(
output_file: &Path,
test_generator: &build::test_gen::LayoutTestGenerator,
test_generator: &bindgen_tests::LayoutTestGenerator,
) -> Result<(), Box<dyn Error>> {
// There are several bindgen-generated types/fields that we can't check:
test_generator
Expand Down
5 changes: 0 additions & 5 deletions ctru-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@
)]
#![doc(html_root_url = "https://rust3ds.github.io/ctru-rs/crates")]

// Prevent linking errors from the standard `test` library when running `cargo 3ds test --lib`.
// See https://github.com/rust-lang/rust-analyzer/issues/14167 for why we use `not(rust_analyzer)`
#[cfg(all(test, not(rust_analyzer)))]
extern crate shim_3ds;

pub mod result;
pub use result::*;

Expand Down
88 changes: 1 addition & 87 deletions ctru-sys/tests/layout_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,99 +9,13 @@
#![feature(custom_test_frameworks)]
#![test_runner(test_runner::run_gdb)]

extern crate shim_3ds;

use std::mem::offset_of;

fn size_of_ret<T, U>(_f: impl Fn(U) -> T) -> usize {
::std::mem::size_of::<T>()
}

macro_rules! size_of {
($ty:ident::$field:ident) => {{
$crate::size_of_ret(|x: $ty| x.$field)
}};
($ty:ty) => {
::std::mem::size_of::<$ty>()
};
($expr:expr) => {
::std::mem::size_of_val(&$expr)
};
}

fn align_of_ret<T, U>(_f: impl Fn(U) -> T) -> usize {
::std::mem::align_of::<T>()
}

macro_rules! align_of {
($ty:ident::$field:ident) => {{
// This matches the semantics of C++ alignof when it is applied to a struct
// member. Packed structs may under-align fields, so we take the minimum
// of the align of the struct and the type of the field itself.
$crate::align_of_ret(|x: $ty| x.$field).min(align_of!($ty))
}};
($ty:ty) => {
::std::mem::align_of::<$ty>()
};
($expr:expr) => {
::std::mem::align_of_val(&$expr)
};
}

#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
mod generated_tests {
use super::*;
use bindgen_tests::{align_of, offset_of, size_of};

use cpp::cpp;
use ctru_sys::*;

include!(concat!(env!("OUT_DIR"), "/generated_layout_test.rs"));
}

mod helper_tests {
macro_rules! packed_struct {
($name:ident, $size:literal) => {
#[repr(C, packed($size))]
struct $name {
a: u8,
b: u16,
c: u32,
d: u64,
}
};
}

packed_struct!(PackedStruct1, 1);
packed_struct!(PackedStruct2, 2);
packed_struct!(PackedStruct4, 4);
packed_struct!(PackedStruct8, 8);

#[test]
fn align_of_matches_cpp() {
// Expected values are based on C++: https://godbolt.org/z/dPnP7nEse
assert_eq!(align_of!(PackedStruct1), 1);
assert_eq!(align_of!(PackedStruct1::a), 1);
assert_eq!(align_of!(PackedStruct1::b), 1);
assert_eq!(align_of!(PackedStruct1::c), 1);
assert_eq!(align_of!(PackedStruct1::d), 1);

assert_eq!(align_of!(PackedStruct2), 2);
assert_eq!(align_of!(PackedStruct2::a), 1);
assert_eq!(align_of!(PackedStruct2::b), 2);
assert_eq!(align_of!(PackedStruct2::c), 2);
assert_eq!(align_of!(PackedStruct2::d), 2);

assert_eq!(align_of!(PackedStruct4), 4);
assert_eq!(align_of!(PackedStruct4::a), 1);
assert_eq!(align_of!(PackedStruct4::b), 2);
assert_eq!(align_of!(PackedStruct4::c), 4);
assert_eq!(align_of!(PackedStruct4::d), 4);

assert_eq!(align_of!(PackedStruct8), 8);
assert_eq!(align_of!(PackedStruct8::a), 1);
assert_eq!(align_of!(PackedStruct8::b), 2);
assert_eq!(align_of!(PackedStruct8::c), 4);
assert_eq!(align_of!(PackedStruct8::d), 8);
}
}
1 change: 1 addition & 0 deletions test-runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ socket = []
ctru-rs = { git = "https://github.com/rust3ds/ctru-rs" }
ctru-sys = { git = "https://github.com/rust3ds/ctru-rs" }
libc = { workspace = true }
shim-3ds = { git = "https://github.com/rust3ds/shim-3ds.git" }
1 change: 1 addition & 0 deletions test-runner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#![feature(exitcode_exit_method)]
#![test_runner(run_gdb)]

extern crate shim_3ds;
extern crate test;

mod console;
Expand Down
Loading