pub fn add_program(
        &mut self,
        program_name: &str,
        program_id: Pubkey,
        process_instruction: Option<ProcessInstructionWithContext>,
    ) {
        let add_bpf = |this: &mut ProgramTest, program_file: PathBuf| {
            let data = read_file(&program_file);
            info!(
                "\"{}\" BPF program from {}{}",
                program_name,
                program_file.display(),
                std::fs::metadata(&program_file)
                    .map(|metadata| {
                        metadata
                            .modified()
                            .map(|time| {
                                format!(
                                    ", modified {}",
                                    HumanTime::from(time)
                                        .to_text_en(Accuracy::Precise, Tense::Past)
                                )
                            })
                            .ok()
                    })
                    .ok()
                    .flatten()
                    .unwrap_or_else(|| "".to_string())
            );

            this.add_account(
                program_id,
                Account {
                    lamports: Rent::default().minimum_balance(data.len()).min(1),
                    data,
                    owner: solana_sdk::bpf_loader::id(),
                    executable: true,
                    rent_epoch: 0,
                },
            );
        };

        let add_native = |this: &mut ProgramTest, process_fn: ProcessInstructionWithContext| {
            info!("\"{}\" program loaded as native code", program_name);
            this.builtins
                .push(Builtin::new(program_name, program_id, process_fn));
        };

        let warn_invalid_program_name = || {
            let valid_program_names = default_shared_object_dirs()
                .iter()
                .filter_map(|dir| dir.read_dir().ok())
                .flat_map(|read_dir| {
                    read_dir.filter_map(|entry| {
                        let path = entry.ok()?.path();
                        if !path.is_file() {
                            return None;
                        }
                        match path.extension()?.to_str()? {
                            "so" => Some(path.file_stem()?.to_os_string()),
                            _ => None,
                        }
                    })
                })
                .collect::<Vec<_>>();

            if valid_program_names.is_empty() {
                // This should be unreachable as `test-bpf` should guarantee at least one shared
                // object exists somewhere.
                warn!("No BPF shared objects found.");
                return;
            }

            warn!(
                "Possible bogus program name. Ensure the program name ({}) \
                matches one of the following recognizable program names:",
                program_name,
            );
            for name in valid_program_names {
                warn!(" - {}", name.to_str().unwrap());
            }
        };

        let program_file = find_file(&format!("{}.so", program_name));
        match (self.prefer_bpf, program_file, process_instruction) {
            // If BPF is preferred (i.e., `test-bpf` is invoked) and a BPF shared object exists,
            // use that as the program data.
            (true, Some(file), _) => add_bpf(self, file),

            // If BPF is not required (i.e., we were invoked with `test`), use the provided
            // processor function as is.
            //
            // TODO: figure out why tests hang if a processor panics when running native code.
            (false, _, Some(process)) => add_native(self, process),

            // Invalid: `test-bpf` invocation with no matching BPF shared object.
            (true, None, _) => {
                warn_invalid_program_name();
                panic!(
                    "Program file data not available for {} ({})",
                    program_name, program_id
                );
            }

            // Invalid: regular `test` invocation without a processor.
            (false, _, None) => {
                panic!(
                    "Program processor not available for {} ({})",
                    program_name, program_id
                );
            }
        }
    }
/// Add a BPF program to the test environment.
///
/// `program_name` will also be used to locate the BPF shared object in the current or fixtures
/// directory.
///
/// If `process_instruction` is provided, the natively built-program may be used instead of the
/// BPF shared object depending on the `BPF_OUT_DIR` environment variable.
Add a BPF program to the test environment.
`program_name` will also be used to locate the BPF shared object in the current or fixtures
directory.

If `process_instruction` is provided, the natively built-program may be used instead of the
BPF shared object depending on the `BPF_OUT_DIR` environment variable.
Add a BPF program to the test environment . ` program_name ` will also be used to locate the BPF shared object in the current or fixtures directory . If ` process_instruction ` is provided the natively built - program may be used instead of the BPF shared object depending on the ` BPF_OUT_DIR ` environment variable .
pub fn add_program(
        &mut self,
        program_name: &str,
        program_id: Pubkey,
        process_instruction: Option<ProcessInstructionWithContext>,
    ) {
        let add_bpf = |this: &mut ProgramTest, program_file: PathBuf| {
            let data = read_file(&program_file);
            info!(
                "\"{}\" BPF program from {}{}",
                program_name,
                program_file.display(),
                std::fs::metadata(&program_file)
                    .map(|metadata| {
                        metadata
                            .modified()
                            .map(|time| {
                                format!(
                                    ", modified {}",
                                    HumanTime::from(time)
                                        .to_text_en(Accuracy::Precise, Tense::Past)
                                )
                            })
                            .ok()
                    })
                    .ok()
                    .flatten()
                    .unwrap_or_else(|| "".to_string())
            );
            this.add_account(
                program_id,
                Account {
                    lamports: Rent::default().minimum_balance(data.len()).min(1),
                    data,
                    owner: solana_sdk::bpf_loader::id(),
                    executable: true,
                    rent_epoch: 0,
                },
            );
        };
        let add_native = |this: &mut ProgramTest, process_fn: ProcessInstructionWithContext| {
            info!("\"{}\" program loaded as native code", program_name);
            this.builtins
                .push(Builtin::new(program_name, program_id, process_fn));
        };
        let warn_invalid_program_name = || {
            let valid_program_names = default_shared_object_dirs()
                .iter()
                .filter_map(|dir| dir.read_dir().ok())
                .flat_map(|read_dir| {
                    read_dir.filter_map(|entry| {
                        let path = entry.ok()?.path();
                        if !path.is_file() {
                            return None;
                        }
                        match path.extension()?.to_str()? {
                            "so" => Some(path.file_stem()?.to_os_string()),
                            _ => None,
                        }
                    })
                })
                .collect::<Vec<_>>();
            if valid_program_names.is_empty() {
                // This should be unreachable as `test-bpf` should guarantee at least one shared
                // object exists somewhere.
                warn!("No BPF shared objects found.");
                return;
            }
            warn!(
                "Possible bogus program name. Ensure the program name ({}) \
                matches one of the following recognizable program names:",
                program_name,
            );
            for name in valid_program_names {
                warn!(" - {}", name.to_str().unwrap());
            }
        };
        let program_file = find_file(&format!("{}.so", program_name));
        match (self.prefer_bpf, program_file, process_instruction) {
            // If BPF is preferred (i.e., `test-bpf` is invoked) and a BPF shared object exists,
            // use that as the program data.
            (true, Some(file), _) => add_bpf(self, file),
            // If BPF is not required (i.e., we were invoked with `test`), use the provided
            // processor function as is.
            //
            // TODO: figure out why tests hang if a processor panics when running native code.
            (false, _, Some(process)) => add_native(self, process),
            // Invalid: `test-bpf` invocation with no matching BPF shared object.
            (true, None, _) => {
                warn_invalid_program_name();
                panic!(
                    "Program file data not available for {} ({})",
                    program_name, program_id
                );
            }
            // Invalid: regular `test` invocation without a processor.
            (false, _, None) => {
                panic!(
                    "Program processor not available for {} ({})",
                    program_name, program_id
                );
            }
        }
    }
pub fn add_program ( & mut self , program_name : & str , program_id : Pubkey , process_instruction : Option < ProcessInstructionWithContext > , ) { let add_bpf = | this : & mut ProgramTest , program_file : PathBuf | { let data = read_file ( & program_file ) ; info ! ( " \" \" " program_name program_file display ( ) std fs metadata ( program_file ) map ( metadata { metadata modified ( ) map ( time { format ( " " HumanTime from ( time ) to_text_en ( Accuracy Precise Tense Past ) ) } ) ok ( ) } ) ok ( ) flatten ( ) unwrap_or_else ( " " to_string ( ) ) ) ; this . add_account ( program_id , Account { lamports : Rent :: default ( ) . minimum_balance ( data . len ( ) ) . min ( 1 ) , data , owner : solana_sdk :: bpf_loader :: id ( ) , executable : true , rent_epoch : 0 , } , ) ; } ; let add_native = | this : & mut ProgramTest , process_fn : ProcessInstructionWithContext | { info ! ( " \" \" " program_name ) ; this . builtins . push ( Builtin :: new ( program_name , program_id , process_fn ) ) ; } ; let warn_invalid_program_name = | | { let valid_program_names = default_shared_object_dirs ( ) . iter ( ) . filter_map ( | dir | dir . read_dir ( ) . ok ( ) ) . flat_map ( | read_dir | { read_dir . filter_map ( | entry | { let path = entry . ok ( ) ? . path ( ) ; if ! path . is_file ( ) { return None ; } match path . extension ( ) ? . to_str ( ) ? { " " => Some ( path . file_stem ( ) ? . to_os_string ( ) ) , _ => None , } } ) } ) . collect :: < Vec < _ > > ( ) ; if valid_program_names . is_empty ( ) { // This should be unreachable as `test-bpf` should guarantee at least one shared // object exists somewhere. warn ! ( " " ) ; return ; } warn ! ( " \
 " program_name ) ; for name in valid_program_names { warn ! ( " " name to_str ( ) unwrap ( ) ) ; } } ; let program_file = find_file ( & format ! ( " " program_name ) ) ; match ( self . prefer_bpf , program_file , process_instruction ) { // If BPF is preferred (i.e., `test-bpf` is invoked) and a BPF shared object exists, // use that as the program data. ( true , Some ( file ) , _ ) => add_bpf ( self , file ) , // If BPF is not required (i.e., we were invoked with `test`), use the provided // processor function as is. // // TODO: figure out why tests hang if a processor panics when running native code. ( false , _ , Some ( process ) ) => add_native ( self , process ) , // Invalid: `test-bpf` invocation with no matching BPF shared object. ( true , None , _ ) => { warn_invalid_program_name ( ) ; panic ! ( " " program_name program_id ) ; } // Invalid: regular `test` invocation without a processor. ( false , _ , None ) => { panic ! ( " " program_name program_id ) ; } } }
Add a BPF program to the test environment.
Add a BPF program to the test environment .
&mut self
program_name
&str
program_id
Pubkey
process_instruction
Option<ProcessInstructionWithContext>