Skip to content

Commit b57f74c

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 416c803 commit b57f74c

File tree

5 files changed

+3264
-8
lines changed

5 files changed

+3264
-8
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
@@ -21,4 +21,5 @@ thiserror = "2.0"
2121
[dev-dependencies]
2222
rstest = "0.24"
2323
tempfile = "3.15"
24-
serial_test = "3.2"
24+
serial_test = "3.2"
25+
insta = { version = "1.42", features = ["yaml"] }

rust/tests/binary_view.rs

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
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;
4-
use binaryninja::symbol::{SymbolBuilder, SymbolType};
5+
use binaryninja::platform::Platform;
6+
use binaryninja::rc::Ref;
7+
use binaryninja::symbol::{Symbol, SymbolBuilder, SymbolType};
58
use rstest::*;
9+
use std::collections::BTreeMap;
610
use std::path::PathBuf;
711

812
#[fixture]
@@ -36,11 +40,12 @@ fn test_binary_saving(_session: &Session) {
3640
// HACK: To prevent us from deadlocking in save_to_path we wait for all main thread actions to finish.
3741
execute_on_main_thread_and_wait(|| {});
3842

43+
let temp_dir = tempfile::tempdir().expect("Failed to create temporary directory");
44+
let temp_path = temp_dir.path().join("atox.obj.new");
3945
// Save the modified file
40-
assert!(view.save_to_path(out_dir.join("atox.obj.new")));
46+
assert!(view.save_to_path(&temp_path));
4147
// Verify that the file exists and is modified.
42-
let new_view =
43-
binaryninja::load(out_dir.join("atox.obj.new")).expect("Failed to load new view");
48+
let new_view = binaryninja::load(temp_path).expect("Failed to load new view");
4449
assert_eq!(new_view.read_vec(0x1560, 4), [0xff, 0xff, 0xff, 0xff]);
4550
}
4651

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

0 commit comments

Comments
 (0)