Skip to content

Commit 251cac7

Browse files
committed
example test for item discovery callback (new_item_found)
1 parent e3167c8 commit 251cac7

File tree

5 files changed

+271
-1
lines changed

5 files changed

+271
-1
lines changed

Cargo.lock

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

bindgen-tests/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ syn = { version = "2.0" }
1515
tempfile = "3"
1616
similar = { version = "2.2.1", features = ["inline"] }
1717
owo-colors = "3.5.0"
18+
regex = "1.7.1"
1819

1920
[features]
2021
logging = ["bindgen/logging"]
@@ -23,4 +24,4 @@ runtime = ["bindgen/runtime"]
2324

2425
__testing_only_extra_assertions = ["bindgen/__testing_only_extra_assertions"]
2526
__testing_only_libclang_9 = ["bindgen/__testing_only_libclang_9"]
26-
__testing_only_libclang_16 = ["bindgen/__testing_only_libclang_16"]
27+
__testing_only_libclang_16 = ["bindgen/__testing_only_libclang_16"]
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Unions
2+
void function_using_anonymous_struct(struct {} arg0);
3+
4+
struct NamedStruct {
5+
};
6+
7+
typedef struct NamedStruct AliasOfNamedStruct;
8+
9+
10+
// Unions
11+
void function_using_anonymous_union(union {} arg0);
12+
13+
union NamedUnion {
14+
};
15+
16+
typedef union NamedUnion AliasOfNamedUnion;
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
use std::cell::RefCell;
2+
use std::collections::HashMap;
3+
use std::rc::Rc;
4+
5+
use regex::Regex;
6+
7+
use bindgen::callbacks::{DiscoveredItem, DiscoveredItemId, ParseCallbacks};
8+
use bindgen::Builder;
9+
10+
#[derive(Debug, Default)]
11+
struct ItemDiscovery(Rc<RefCell<ItemCache>>);
12+
13+
pub type ItemCache = HashMap<DiscoveredItemId, DiscoveredItem>;
14+
15+
impl ParseCallbacks for ItemDiscovery {
16+
fn new_item_found(&self, _id: DiscoveredItemId, _item: DiscoveredItem) {
17+
self.0.borrow_mut().insert(_id, _item);
18+
}
19+
}
20+
#[test]
21+
pub fn test_item_discovery_callback() {
22+
let discovery = ItemDiscovery::default();
23+
let info = Rc::clone(&discovery.0);
24+
25+
Builder::default()
26+
.header(concat!(
27+
env!("CARGO_MANIFEST_DIR"),
28+
"/tests/parse_callbacks/item_discovery_callback/header_item_discovery.h"
29+
))
30+
.parse_callbacks(Box::new(discovery))
31+
.generate()
32+
.expect("TODO: panic message");
33+
34+
let expected = ItemCache::from([
35+
(
36+
DiscoveredItemId::new(10),
37+
DiscoveredItem::Struct {
38+
original_name: Some("NamedStruct".to_string()),
39+
final_name: "NamedStruct".to_string(),
40+
},
41+
),
42+
(
43+
DiscoveredItemId::new(11),
44+
DiscoveredItem::Alias {
45+
alias_name: "AliasOfNamedStruct".to_string(),
46+
alias_for: DiscoveredItemId::new(10),
47+
},
48+
),
49+
(
50+
DiscoveredItemId::new(20),
51+
DiscoveredItem::Union {
52+
original_name: Some("NamedUnion".to_string()),
53+
final_name: "NamedUnion".to_string(),
54+
},
55+
),
56+
(
57+
DiscoveredItemId::new(21),
58+
DiscoveredItem::Alias {
59+
alias_name: "AliasOfNamedUnion".to_string(),
60+
alias_for: DiscoveredItemId::new(20),
61+
},
62+
),
63+
(
64+
DiscoveredItemId::new(30),
65+
DiscoveredItem::Struct {
66+
original_name: None,
67+
final_name: "_bindgen_ty_*".to_string(),
68+
},
69+
),
70+
(
71+
DiscoveredItemId::new(40),
72+
DiscoveredItem::Union {
73+
original_name: None,
74+
final_name: "_bindgen_ty_*".to_string(),
75+
},
76+
)]);
77+
78+
compare_item_caches(info.borrow().clone(), expected);
79+
}
80+
81+
pub fn compare_item_caches(generated: ItemCache, expected: ItemCache) {
82+
// We can't use a simple Eq::eq comparison because of two reasons:
83+
// - anonymous structs/unions will have a final name generated by bindgen which may change
84+
// if the header file or the bindgen logic is altered
85+
// - aliases have a DiscoveredItemId that we can't directly compare for the same instability reasons
86+
for expected_item in expected.values() {
87+
let found = generated.iter().find(|(_generated_id, generated_item)| {
88+
compare_item_info(
89+
expected_item,
90+
generated_item,
91+
&expected,
92+
&generated,
93+
)
94+
});
95+
96+
if found.is_none() {
97+
panic!(
98+
"Missing Expected Item: {:#?}\n in {:#?}",
99+
expected_item, generated
100+
);
101+
}
102+
}
103+
}
104+
105+
fn compare_item_info(
106+
expected_item: &DiscoveredItem,
107+
generated_item: &DiscoveredItem,
108+
expected: &ItemCache,
109+
generated: &ItemCache,
110+
) -> bool {
111+
if std::mem::discriminant(expected_item) !=
112+
std::mem::discriminant(generated_item)
113+
{
114+
return false;
115+
}
116+
117+
match generated_item {
118+
DiscoveredItem::Struct { .. } => {
119+
compare_struct_info(expected_item, generated_item)
120+
}
121+
DiscoveredItem::Union { .. } => {
122+
compare_union_info(expected_item, generated_item)
123+
}
124+
DiscoveredItem::Alias { .. } => compare_alias_info(
125+
expected_item,
126+
generated_item,
127+
expected,
128+
generated,
129+
),
130+
}
131+
}
132+
133+
pub fn compare_names(expected_name: &str, generated_name: &str) -> bool {
134+
if let Ok(regex) = Regex::new(expected_name) {
135+
regex.is_match(generated_name)
136+
} else {
137+
false
138+
}
139+
}
140+
141+
pub fn compare_struct_info(
142+
expected_item: &DiscoveredItem,
143+
generated_item: &DiscoveredItem,
144+
) -> bool {
145+
let DiscoveredItem::Struct {
146+
original_name: expected_original_name,
147+
final_name: expected_final_name,
148+
} = expected_item
149+
else {
150+
unreachable!()
151+
};
152+
153+
let DiscoveredItem::Struct {
154+
original_name: generated_original_name,
155+
final_name: generated_final_name,
156+
} = generated_item
157+
else {
158+
unreachable!()
159+
};
160+
161+
if !compare_names(expected_final_name, generated_final_name) {
162+
return false;
163+
}
164+
165+
match (expected_original_name, generated_original_name) {
166+
(None, None) => true,
167+
(Some(expected_original_name), Some(generated_original_name)) => {
168+
compare_names(expected_original_name, generated_original_name)
169+
}
170+
_ => false,
171+
}
172+
}
173+
174+
pub fn compare_union_info(
175+
expected_item: &DiscoveredItem,
176+
generated_item: &DiscoveredItem,
177+
) -> bool {
178+
let DiscoveredItem::Union {
179+
original_name: expected_original_name,
180+
final_name: expected_final_name,
181+
} = expected_item
182+
else {
183+
unreachable!()
184+
};
185+
186+
let DiscoveredItem::Union {
187+
original_name: generated_original_name,
188+
final_name: generated_final_name,
189+
} = generated_item
190+
else {
191+
unreachable!()
192+
};
193+
194+
if !compare_names(expected_final_name, generated_final_name) {
195+
return false;
196+
}
197+
198+
match (expected_original_name, generated_original_name) {
199+
(None, None) => true,
200+
(Some(expected_original_name), Some(generated_original_name)) => {
201+
compare_names(expected_original_name, generated_original_name)
202+
}
203+
_ => false,
204+
}
205+
}
206+
207+
pub fn compare_alias_info(
208+
expected_item: &DiscoveredItem,
209+
generated_item: &DiscoveredItem,
210+
expected: &ItemCache,
211+
generated: &ItemCache,
212+
) -> bool {
213+
let DiscoveredItem::Alias {
214+
alias_name: expected_alias_name,
215+
alias_for: expected_alias_for,
216+
} = expected_item
217+
else {
218+
unreachable!()
219+
};
220+
221+
let DiscoveredItem::Alias {
222+
alias_name: generated_alias_name,
223+
alias_for: generated_alias_for,
224+
} = generated_item
225+
else {
226+
unreachable!()
227+
};
228+
229+
if !compare_names(expected_alias_name, generated_alias_name) {
230+
return false;
231+
}
232+
233+
// Assumes correct test definition
234+
let expected_aliased = expected.get(expected_alias_for).unwrap();
235+
236+
// We must have the aliased type in the cache
237+
let generated_aliased =
238+
if let Some(generated_aliased) = generated.get(generated_alias_for) {
239+
generated_aliased
240+
} else {
241+
return false;
242+
};
243+
244+
compare_item_info(
245+
expected_aliased,
246+
generated_aliased,
247+
expected,
248+
generated,
249+
)
250+
}

bindgen-tests/tests/parse_callbacks/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
mod item_discovery_callback;
2+
13
use bindgen::callbacks::*;
24
use bindgen::FieldVisibilityKind;
35

0 commit comments

Comments
 (0)