Mercurial > crates > nonstick
diff libpam-sys/libpam-sys-test/build.rs @ 110:2346fd501b7a
Add tests for constants and do other macro niceties.
- Adds tests for all the constants. Pretty sweet.
- Moves documentation for cfg-pam-impl macro to `libpam-sys`.
- Renames `Illumos` to `Sun`.
- other stuff
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sun, 29 Jun 2025 02:15:46 -0400 |
parents | |
children | 04105e9a7de8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpam-sys/libpam-sys-test/build.rs Sun Jun 29 02:15:46 2025 -0400 @@ -0,0 +1,103 @@ +use bindgen::MacroTypeVariation; +use libpam_sys_impls::cfg_pam_impl; +use quote::ToTokens; +use std::path::PathBuf; +use std::{env, fs}; +use syn::{Item, ItemConst}; + +fn main() { + generate_const_test(); +} + +#[cfg_pam_impl("LinuxPam")] +fn test_config() -> TestConfig { + TestConfig { + headers: vec![ + "security/_pam_types.h".into(), + "security/pam_appl.h".into(), + "security/pam_ext.h".into(), + "security/pam_modules.h".into(), + ], + ignore_consts: vec!["__LINUX_PAM__".into(), "__LINUX_PAM_MINOR__".into()], + } +} + +#[cfg_pam_impl("OpenPam")] +fn test_config() -> TestConfig { + TestConfig { + headers: vec![ + "security/pam_types.h", + "security/openpam.h", + "security/pam_appl.h", + "security/pam_constants.h", + ], + ignore_consts: vec![], + } +} + +#[cfg_pam_impl(not(any("LinuxPam", "OpenPam")))] +fn test_config() -> TestConfig { + panic!("This PAM implementation is not yet tested.") +} + +fn generate_const_test() { + let config = test_config(); + let builder = bindgen::Builder::default() + .header_contents("_.h", &config.header_contents()) + .merge_extern_blocks(true) + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .blocklist_type(".*") + .blocklist_function(".*") + .allowlist_var(".*") + .default_macro_constant_type(MacroTypeVariation::Unsigned); + + let generated = builder.generate().unwrap().to_string(); + let file = syn::parse_file(&generated).unwrap(); + let mut tests = vec![]; + tests.push("{".into()); + tests.extend( + file.items + .iter() + .filter_map(|item| { + if let Item::Const(item) = item { + Some(item) + } else { + None + } + }) + .filter(|item| config.should_check_const(item)) + .map(|item| { + let tokens = item.expr.to_token_stream(); + format!( + "assert_eq!({tokens}, libpam_sys::{name});", + name = item.ident + ) + }), + ); + tests.push("}".into()); + fs::write( + PathBuf::from(env::var("OUT_DIR").unwrap()).join("constant_test.rs"), + tests.join("\n"), + ) + .unwrap(); +} + +struct TestConfig { + headers: Vec<String>, + ignore_consts: Vec<String>, +} + +impl TestConfig { + fn header_contents(&self) -> String { + let vec: Vec<_> = self + .headers + .iter() + .map(|h| format!("#include <{h}>\n")) + .collect(); + vec.join("") + } + + fn should_check_const(&self, item: &ItemConst) -> bool { + !self.ignore_consts.contains(&item.ident.to_string()) + } +}