Skip to main content

cairo_program_runner_lib/
test_utils.rs

1use std::rc::Rc;
2
3use crate::hints::types::Task;
4use crate::hints::vars;
5use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData;
6use cairo_vm::hint_processor::hint_processor_definition::HintExtension;
7use cairo_vm::hint_processor::hint_processor_definition::HintReference;
8use cairo_vm::serde::deserialize_program::ApTracking;
9use cairo_vm::types::exec_scope::ExecutionScopes;
10use cairo_vm::types::relocatable::MaybeRelocatable;
11use cairo_vm::types::relocatable::Relocatable;
12use cairo_vm::vm::vm_core::VirtualMachine;
13
14/// Test helper: Create a HashMap of HintReferences for testing.
15/// Output:
16/// {
17///     0: HintReference::new_simple(-num),
18///     1: HintReference::new_simple(-num + 1),
19///     ...
20///     num - 1: HintReference::new_simple(-1),
21///     num: HintReference::new_simple(0),
22/// }
23pub fn prepare_refrences_for_test(num: i32) -> std::collections::HashMap<usize, HintReference> {
24    let mut references = std::collections::HashMap::<usize, HintReference>::new();
25    for i in 0..num {
26        references.insert(i as usize, HintReference::new_simple(i - num));
27    }
28    references
29}
30
31/// Test helper: Create a HashMap of HintReferences for testing, keyed by name.
32/// Output:
33/// {
34///     "name1": HintReference::new_simple(-num),
35///     "name2": HintReference::new_simple(-num + 1),
36///     ...
37///     "nameN": HintReference::new_simple(-1),
38/// }
39/// where num is the length of names.
40pub fn fill_ids_data_for_test(names: &[&str]) -> std::collections::HashMap<String, HintReference> {
41    let references = prepare_refrences_for_test(names.len() as i32);
42    let mut ids_data = std::collections::HashMap::<String, HintReference>::new();
43    for (i, name) in names.iter().enumerate() {
44        ids_data.insert(name.to_string(), references.get(&i).unwrap().clone());
45    }
46    ids_data
47}
48
49/// Test helper: Create a HashMap of HintReferences for testing, keyed by name and offset.
50/// example output: (notice that some offsets are skipped)
51/// {
52/// "name1": HintReference::new_simple(-1),
53/// "name2": HintReference::new_simple(-3),
54/// "name3": HintReference::new_simple(-10)
55/// ...
56/// },
57pub fn prepare_non_continuous_ids_data_for_test(
58    pairs: &[(&str, i32)],
59) -> std::collections::HashMap<String, HintReference> {
60    let mut ids_data = std::collections::HashMap::<String, HintReference>::new();
61    for (name, offset) in pairs {
62        ids_data.insert(name.to_string(), HintReference::new_simple(*offset));
63    }
64    ids_data
65}
66
67/// Utility function to extract all hint code strings from a HintExtension at a given PC.
68pub fn get_hint_codes_at_pc(hint_extension: &HintExtension, pc: Relocatable) -> Vec<&str> {
69    hint_extension
70        .get(&pc)
71        .expect("Hint extension should contain the hint at the given PC")
72        .iter()
73        .map(|hint_any| {
74            hint_any
75                .downcast_ref::<HintProcessorData>()
76                .expect("Hint at PC is not a HintProcessorData")
77                .code
78                .as_str()
79        })
80        .collect()
81}
82
83/// Utility: Prepares a VM, ids_data, exec_scopes, ap_tracking, and pointers for bootloader tests.
84/// After this function is executed the VM has 3 segments, and the program header is at (2, 0).
85/// The `task` is inserted into the execution scopes. `load_program_hint` should succeed after this
86/// function.
87pub fn prepare_vm_for_load_program_loading_test(
88    task: Rc<Task>,
89) -> (
90    VirtualMachine,
91    std::collections::HashMap<String, HintReference>,
92    ExecutionScopes,
93    ApTracking,
94    usize,       // expected_program_data_segment_index
95    Relocatable, // program_header_ptr
96    Rc<Task>,
97) {
98    let mut vm = VirtualMachine::new(false, false);
99    vm.set_fp(3);
100    vm.segments.add();
101    vm.segments.add();
102    let _ = vm.segments.load_data(
103        Relocatable::from((1, 0)),
104        &[
105            MaybeRelocatable::from((2, 0)),
106            MaybeRelocatable::from((2, 0)),
107            MaybeRelocatable::from((2, 0)),
108        ],
109    );
110
111    let ids_data =
112        fill_ids_data_for_test(&["program_segment_ptr", "program_header", "program_data_ptr"]);
113    let expected_program_data_segment_index = vm.segments.num_segments();
114    let program_header_ptr = Relocatable::from((2, 0));
115    let mut exec_scopes = ExecutionScopes::new();
116    exec_scopes.insert_value(vars::TASK, task.clone());
117    exec_scopes.insert_value(vars::PROGRAM_DATA_BASE, program_header_ptr);
118    let ap_tracking = ApTracking::new();
119    (
120        vm,
121        ids_data,
122        exec_scopes,
123        ap_tracking,
124        expected_program_data_segment_index,
125        program_header_ptr,
126        task,
127    )
128}