comparison 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
comparison
equal deleted inserted replaced
109:bb465393621f 110:2346fd501b7a
1 use bindgen::MacroTypeVariation;
2 use libpam_sys_impls::cfg_pam_impl;
3 use quote::ToTokens;
4 use std::path::PathBuf;
5 use std::{env, fs};
6 use syn::{Item, ItemConst};
7
8 fn main() {
9 generate_const_test();
10 }
11
12 #[cfg_pam_impl("LinuxPam")]
13 fn test_config() -> TestConfig {
14 TestConfig {
15 headers: vec![
16 "security/_pam_types.h".into(),
17 "security/pam_appl.h".into(),
18 "security/pam_ext.h".into(),
19 "security/pam_modules.h".into(),
20 ],
21 ignore_consts: vec!["__LINUX_PAM__".into(), "__LINUX_PAM_MINOR__".into()],
22 }
23 }
24
25 #[cfg_pam_impl("OpenPam")]
26 fn test_config() -> TestConfig {
27 TestConfig {
28 headers: vec![
29 "security/pam_types.h",
30 "security/openpam.h",
31 "security/pam_appl.h",
32 "security/pam_constants.h",
33 ],
34 ignore_consts: vec![],
35 }
36 }
37
38 #[cfg_pam_impl(not(any("LinuxPam", "OpenPam")))]
39 fn test_config() -> TestConfig {
40 panic!("This PAM implementation is not yet tested.")
41 }
42
43 fn generate_const_test() {
44 let config = test_config();
45 let builder = bindgen::Builder::default()
46 .header_contents("_.h", &config.header_contents())
47 .merge_extern_blocks(true)
48 .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
49 .blocklist_type(".*")
50 .blocklist_function(".*")
51 .allowlist_var(".*")
52 .default_macro_constant_type(MacroTypeVariation::Unsigned);
53
54 let generated = builder.generate().unwrap().to_string();
55 let file = syn::parse_file(&generated).unwrap();
56 let mut tests = vec![];
57 tests.push("{".into());
58 tests.extend(
59 file.items
60 .iter()
61 .filter_map(|item| {
62 if let Item::Const(item) = item {
63 Some(item)
64 } else {
65 None
66 }
67 })
68 .filter(|item| config.should_check_const(item))
69 .map(|item| {
70 let tokens = item.expr.to_token_stream();
71 format!(
72 "assert_eq!({tokens}, libpam_sys::{name});",
73 name = item.ident
74 )
75 }),
76 );
77 tests.push("}".into());
78 fs::write(
79 PathBuf::from(env::var("OUT_DIR").unwrap()).join("constant_test.rs"),
80 tests.join("\n"),
81 )
82 .unwrap();
83 }
84
85 struct TestConfig {
86 headers: Vec<String>,
87 ignore_consts: Vec<String>,
88 }
89
90 impl TestConfig {
91 fn header_contents(&self) -> String {
92 let vec: Vec<_> = self
93 .headers
94 .iter()
95 .map(|h| format!("#include <{h}>\n"))
96 .collect();
97 vec.join("")
98 }
99
100 fn should_check_const(&self, item: &ItemConst) -> bool {
101 !self.ignore_consts.contains(&item.ident.to_string())
102 }
103 }