Skip to content

Commit e9da875

Browse files
committed
Add test_deterministic_functions to Rust API unit tests
This test makes sure that initial analysis is not tainting functions
1 parent cb892be commit e9da875

File tree

5 files changed

+3261
-11
lines changed

5 files changed

+3261
-11
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.

rust/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ thiserror = "2.0"
2222
[dev-dependencies]
2323
rstest = "0.24"
2424
tempfile = "3.15"
25-
serial_test = "3.2"
25+
serial_test = "3.2"
26+
insta = { version = "1.42", features = ["yaml"] }

rust/tests/binary_view.rs

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use binaryninja::binary_view::{AnalysisState, BinaryViewBase, BinaryViewExt};
2+
use binaryninja::function::Function;
23
use binaryninja::headless::Session;
34
use binaryninja::main_thread::execute_on_main_thread_and_wait;
45
use binaryninja::symbol::{SymbolBuilder, SymbolType};
@@ -32,15 +33,13 @@ fn test_binary_saving() {
3233
// HACK: To prevent us from deadlocking in save_to_path we wait for all main thread actions to finish.
3334
execute_on_main_thread_and_wait(|| {});
3435

36+
let temp_dir = tempfile::tempdir().expect("Failed to create temporary directory");
37+
let temp_path = temp_dir.path().join("atox.obj.new");
3538
// Save the modified file
36-
assert!(view.save_to_path(out_dir.join("atox.obj.new")));
39+
assert!(view.save_to_path(&temp_path));
3740
// Verify that the file exists and is modified.
38-
let new_view =
39-
binaryninja::load(out_dir.join("atox.obj.new")).expect("Failed to load new view");
40-
assert_eq!(
41-
new_view.read_vec(contents_addr, 4),
42-
[0xff, 0xff, 0xff, 0xff]
43-
);
41+
let new_view = binaryninja::load(temp_path).expect("Failed to load new view");
42+
assert_eq!(new_view.read_vec(contents_addr, 4), [0xff, 0xff, 0xff, 0xff]);
4443
}
4544

4645
#[test]
@@ -58,12 +57,53 @@ fn test_binary_saving_database() {
5857
// Verify that we modified the binary
5958
assert_eq!(entry_function.symbol().raw_name().as_str(), "test");
6059
// Save the modified database.
61-
assert!(view.file().create_database(out_dir.join("atox.obj.bndb")));
60+
let temp_dir = tempfile::tempdir().expect("Failed to create temporary directory");
61+
let temp_path = temp_dir.path().join("atox.obj.bndb");
62+
assert!(view.file().create_database(&temp_path));
6263
// Verify that the file exists and is modified.
63-
let new_view =
64-
binaryninja::load(out_dir.join("atox.obj.bndb")).expect("Failed to load new view");
64+
let new_view = binaryninja::load(temp_path).expect("Failed to load new view");
6565
let new_entry_function = new_view
6666
.entry_point_function()
6767
.expect("Failed to get entry point function");
6868
assert_eq!(new_entry_function.symbol().raw_name().as_str(), "test");
6969
}
70+
71+
// This is what we store to check if a function matches the expected function.
72+
// See `test_deterministic_functions` for details.
73+
#[derive(Debug, PartialEq)]
74+
pub struct FunctionSnapshot {
75+
name: String,
76+
platform: Ref<Platform>,
77+
symbol: Ref<Symbol>,
78+
}
79+
80+
impl From<&Function> for FunctionSnapshot {
81+
fn from(func: &Function) -> Self {
82+
Self {
83+
name: func.symbol().raw_name().to_string(),
84+
platform: func.platform().to_owned(),
85+
symbol: func.symbol().to_owned(),
86+
}
87+
}
88+
}
89+
90+
#[rstest]
91+
fn test_deterministic_functions(session: &Session) {
92+
// Test to make sure that analysis always collects the same information on functions.
93+
let out_dir = env!("OUT_DIR").parse::<PathBuf>().unwrap();
94+
for entry in std::fs::read_dir(out_dir).expect("Failed to read OUT_DIR") {
95+
let entry = entry.expect("Failed to read directory entry");
96+
let path = entry.path();
97+
if path.is_file() {
98+
let view = session.load(&path).expect("Failed to load view");
99+
assert_eq!(view.analysis_progress().state, AnalysisState::IdleState);
100+
let functions: BTreeMap<u64, FunctionSnapshot> = view
101+
.functions()
102+
.iter()
103+
.map(|f| (f.start(), FunctionSnapshot::from(f.as_ref())))
104+
.collect();
105+
let snapshot_name = path.file_stem().unwrap().to_str().unwrap();
106+
insta::assert_debug_snapshot!(snapshot_name, functions);
107+
}
108+
}
109+
}

0 commit comments

Comments
 (0)