diff --git a/src/vm/run_context.rs b/src/vm/run_context.rs index 2495d608eb..9d5ba07e7d 100644 --- a/src/vm/run_context.rs +++ b/src/vm/run_context.rs @@ -17,7 +17,7 @@ pub struct RunContext { impl RunContext { ///Returns the encoded instruction (the value at pc) and the immediate value (the value at pc + 1, if it exists in the memory). - fn get_instruction_encoding( + pub fn get_instruction_encoding( &self, ) -> Result<(&BigInt, Option<&MaybeRelocatable>), VirtualMachineError> { let encoding_ref: &BigInt; @@ -71,3 +71,395 @@ impl RunContext { return Ok(base_addr.add_num_addr(instruction.off1.clone(), Some(self.prime.clone()))); } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::vm::instruction::{ApUpdate, FpUpdate, Opcode, PcUpdate, Res}; + use crate::vm::vm_core::VirtualMachineError; + use std::collections::HashMap; + + #[test] + fn get_instruction_encoding_successful_without_imm() { + let mut run_context = RunContext { + memory: Memory::new(), + pc: MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + ap: MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + fp: MaybeRelocatable::Int(BigInt::from_i32(6).unwrap()), + prime: BigInt::from_i32(39).unwrap(), + }; + + run_context.memory.insert( + &MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + &MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + ); + if let Ok((num_ref, None)) = run_context.get_instruction_encoding() { + assert_eq!(num_ref.clone(), BigInt::from_i32(5).unwrap()); + } else { + assert!(false); + } + } + + #[test] + fn get_instruction_encoding_successful_with_imm() { + let mut run_context = RunContext { + memory: Memory::new(), + pc: MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + ap: MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + fp: MaybeRelocatable::Int(BigInt::from_i32(6).unwrap()), + prime: BigInt::from_i32(39).unwrap(), + }; + + run_context.memory.insert( + &MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + &MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + ); + run_context.memory.insert( + &MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + &MaybeRelocatable::Int(BigInt::from_i32(6).unwrap()), + ); + if let Ok((num_ref, Some(&MaybeRelocatable::Int(ref imm_addr_num_ref)))) = + run_context.get_instruction_encoding() + { + assert_eq!(num_ref.clone(), BigInt::from_i32(5).unwrap()); + assert_eq!(imm_addr_num_ref.clone(), BigInt::from_i32(6).unwrap()); + } else { + assert!(false); + } + } + + #[test] + fn get_instruction_encoding_unsuccesful() { + let mut run_context = RunContext { + memory: Memory::new(), + pc: MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + ap: MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + fp: MaybeRelocatable::Int(BigInt::from_i32(6).unwrap()), + prime: BigInt::from_i32(39).unwrap(), + }; + + run_context.memory.insert( + &MaybeRelocatable::Int(BigInt::from_i32(7).unwrap()), + &MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + ); + if let Err(error) = run_context.get_instruction_encoding() { + assert_eq!(error, VirtualMachineError::InvalidInstructionEncodingError); + } else { + assert!(false); + } + } + + #[test] + fn compute_dst_addr_for_ap_register() { + let instruction = Instruction { + off0: BigInt::from_i32(1).unwrap(), + off1: BigInt::from_i32(2).unwrap(), + off2: BigInt::from_i32(3).unwrap(), + imm: None, + dst_register: Register::AP, + op0_register: Register::FP, + op1_addr: Op1Addr::AP, + res: Res::ADD, + pc_update: PcUpdate::REGULAR, + ap_update: ApUpdate::REGULAR, + fp_update: FpUpdate::REGULAR, + opcode: Opcode::NOP, + }; + + let run_context = RunContext { + memory: Memory::new(), + pc: MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + ap: MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + fp: MaybeRelocatable::Int(BigInt::from_i32(6).unwrap()), + prime: BigInt::from_i32(39).unwrap(), + }; + if let MaybeRelocatable::Int(num) = run_context.compute_dst_addr(&instruction) { + assert_eq!(num, BigInt::from_i32(6).unwrap()); + } else { + assert!(false); + } + } + + #[test] + fn compute_dst_addr_for_fp_register() { + let instruction = Instruction { + off0: BigInt::from_i32(1).unwrap(), + off1: BigInt::from_i32(2).unwrap(), + off2: BigInt::from_i32(3).unwrap(), + imm: None, + dst_register: Register::FP, + op0_register: Register::AP, + op1_addr: Op1Addr::AP, + res: Res::ADD, + pc_update: PcUpdate::REGULAR, + ap_update: ApUpdate::REGULAR, + fp_update: FpUpdate::REGULAR, + opcode: Opcode::NOP, + }; + + let run_context = RunContext { + memory: Memory::new(), + pc: MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + ap: MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + fp: MaybeRelocatable::Int(BigInt::from_i32(6).unwrap()), + prime: BigInt::from_i32(39).unwrap(), + }; + if let MaybeRelocatable::Int(num) = run_context.compute_dst_addr(&instruction) { + assert_eq!(num, BigInt::from_i32(7).unwrap()); + } else { + assert!(false); + } + } + + #[test] + fn compute_op0_addr_for_ap_register() { + let instruction = Instruction { + off0: BigInt::from_i32(1).unwrap(), + off1: BigInt::from_i32(2).unwrap(), + off2: BigInt::from_i32(3).unwrap(), + imm: None, + dst_register: Register::AP, + op0_register: Register::AP, + op1_addr: Op1Addr::AP, + res: Res::ADD, + pc_update: PcUpdate::REGULAR, + ap_update: ApUpdate::REGULAR, + fp_update: FpUpdate::REGULAR, + opcode: Opcode::NOP, + }; + + let run_context = RunContext { + memory: Memory::new(), + pc: MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + ap: MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + fp: MaybeRelocatable::Int(BigInt::from_i32(6).unwrap()), + prime: BigInt::from_i32(39).unwrap(), + }; + if let MaybeRelocatable::Int(num) = run_context.compute_op0_addr(&instruction) { + assert_eq!(num, BigInt::from_i32(7).unwrap()); + } else { + assert!(false); + } + } + + #[test] + fn compute_op0_addr_for_fp_register() { + let instruction = Instruction { + off0: BigInt::from_i32(1).unwrap(), + off1: BigInt::from_i32(2).unwrap(), + off2: BigInt::from_i32(3).unwrap(), + imm: None, + dst_register: Register::FP, + op0_register: Register::FP, + op1_addr: Op1Addr::AP, + res: Res::ADD, + pc_update: PcUpdate::REGULAR, + ap_update: ApUpdate::REGULAR, + fp_update: FpUpdate::REGULAR, + opcode: Opcode::NOP, + }; + + let run_context = RunContext { + memory: Memory::new(), + pc: MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + ap: MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + fp: MaybeRelocatable::Int(BigInt::from_i32(6).unwrap()), + prime: BigInt::from_i32(39).unwrap(), + }; + if let MaybeRelocatable::Int(num) = run_context.compute_op0_addr(&instruction) { + assert_eq!(num, BigInt::from_i32(8).unwrap()); + } else { + assert!(false); + } + } + + #[test] + fn compute_op1_addr_for_fp_op1_addr() { + let instruction = Instruction { + off0: BigInt::from_i32(1).unwrap(), + off1: BigInt::from_i32(2).unwrap(), + off2: BigInt::from_i32(3).unwrap(), + imm: None, + dst_register: Register::FP, + op0_register: Register::AP, + op1_addr: Op1Addr::FP, + res: Res::ADD, + pc_update: PcUpdate::REGULAR, + ap_update: ApUpdate::REGULAR, + fp_update: FpUpdate::REGULAR, + opcode: Opcode::NOP, + }; + + let run_context = RunContext { + memory: Memory::new(), + pc: MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + ap: MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + fp: MaybeRelocatable::Int(BigInt::from_i32(6).unwrap()), + prime: BigInt::from_i32(39).unwrap(), + }; + if let Ok(MaybeRelocatable::Int(num)) = run_context.compute_op1_addr(&instruction, None) { + assert_eq!(num, BigInt::from_i32(8).unwrap()); + } else { + assert!(false); + } + } + + #[test] + fn compute_op1_addr_for_ap_op1_addr() { + let instruction = Instruction { + off0: BigInt::from_i32(1).unwrap(), + off1: BigInt::from_i32(2).unwrap(), + off2: BigInt::from_i32(3).unwrap(), + imm: None, + dst_register: Register::FP, + op0_register: Register::AP, + op1_addr: Op1Addr::AP, + res: Res::ADD, + pc_update: PcUpdate::REGULAR, + ap_update: ApUpdate::REGULAR, + fp_update: FpUpdate::REGULAR, + opcode: Opcode::NOP, + }; + + let run_context = RunContext { + memory: Memory::new(), + pc: MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + ap: MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + fp: MaybeRelocatable::Int(BigInt::from_i32(6).unwrap()), + prime: BigInt::from_i32(39).unwrap(), + }; + if let Ok(MaybeRelocatable::Int(num)) = run_context.compute_op1_addr(&instruction, None) { + assert_eq!(num, BigInt::from_i32(7).unwrap()); + } else { + assert!(false); + } + } + + #[test] + fn compute_op1_addr_for_imm_op1_addr_correct_off2() { + let instruction = Instruction { + off0: BigInt::from_i32(1).unwrap(), + off1: BigInt::from_i32(2).unwrap(), + off2: BigInt::from_i32(1).unwrap(), + imm: None, + dst_register: Register::FP, + op0_register: Register::AP, + op1_addr: Op1Addr::IMM, + res: Res::ADD, + pc_update: PcUpdate::REGULAR, + ap_update: ApUpdate::REGULAR, + fp_update: FpUpdate::REGULAR, + opcode: Opcode::NOP, + }; + + let run_context = RunContext { + memory: Memory::new(), + pc: MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + ap: MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + fp: MaybeRelocatable::Int(BigInt::from_i32(6).unwrap()), + prime: BigInt::from_i32(39).unwrap(), + }; + if let Ok(MaybeRelocatable::Int(num)) = run_context.compute_op1_addr(&instruction, None) { + assert_eq!(num, BigInt::from_i32(6).unwrap()); + } else { + assert!(false); + } + } + + #[test] + fn compute_op1_addr_for_imm_op1_addr_incorrect_off2() { + let instruction = Instruction { + off0: BigInt::from_i32(1).unwrap(), + off1: BigInt::from_i32(2).unwrap(), + off2: BigInt::from_i32(3).unwrap(), + imm: None, + dst_register: Register::FP, + op0_register: Register::AP, + op1_addr: Op1Addr::IMM, + res: Res::ADD, + pc_update: PcUpdate::REGULAR, + ap_update: ApUpdate::REGULAR, + fp_update: FpUpdate::REGULAR, + opcode: Opcode::NOP, + }; + + let run_context = RunContext { + memory: Memory::new(), + pc: MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + ap: MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + fp: MaybeRelocatable::Int(BigInt::from_i32(6).unwrap()), + prime: BigInt::from_i32(39).unwrap(), + }; + if let Err(error) = run_context.compute_op1_addr(&instruction, None) { + assert_eq!(error, VirtualMachineError::ImmShouldBe1Error); + } else { + assert!(false); + } + } + + #[test] + fn compute_op1_addr_for_op0_op1_addr_with_op0() { + let instruction = Instruction { + off0: BigInt::from_i32(1).unwrap(), + off1: BigInt::from_i32(2).unwrap(), + off2: BigInt::from_i32(1).unwrap(), + imm: None, + dst_register: Register::FP, + op0_register: Register::AP, + op1_addr: Op1Addr::OP0, + res: Res::ADD, + pc_update: PcUpdate::REGULAR, + ap_update: ApUpdate::REGULAR, + fp_update: FpUpdate::REGULAR, + opcode: Opcode::NOP, + }; + + let run_context = RunContext { + memory: Memory::new(), + pc: MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + ap: MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + fp: MaybeRelocatable::Int(BigInt::from_i32(6).unwrap()), + prime: BigInt::from_i32(39).unwrap(), + }; + + let op0 = MaybeRelocatable::Int(BigInt::from_i32(7).unwrap()); + if let Ok(MaybeRelocatable::Int(num)) = + run_context.compute_op1_addr(&instruction, Some(op0)) + { + assert_eq!(num, BigInt::from_i32(9).unwrap()); + } else { + assert!(false); + } + } + + #[test] + fn compute_op1_addr_for_op0_op1_addr_without_op0() { + let instruction = Instruction { + off0: BigInt::from_i32(1).unwrap(), + off1: BigInt::from_i32(2).unwrap(), + off2: BigInt::from_i32(3).unwrap(), + imm: None, + dst_register: Register::FP, + op0_register: Register::AP, + op1_addr: Op1Addr::OP0, + res: Res::ADD, + pc_update: PcUpdate::REGULAR, + ap_update: ApUpdate::REGULAR, + fp_update: FpUpdate::REGULAR, + opcode: Opcode::NOP, + }; + + let run_context = RunContext { + memory: Memory::new(), + pc: MaybeRelocatable::Int(BigInt::from_i32(4).unwrap()), + ap: MaybeRelocatable::Int(BigInt::from_i32(5).unwrap()), + fp: MaybeRelocatable::Int(BigInt::from_i32(6).unwrap()), + prime: BigInt::from_i32(39).unwrap(), + }; + if let Err(error) = run_context.compute_op1_addr(&instruction, None) { + assert_eq!(error, VirtualMachineError::UnknownOp0Error); + } else { + assert!(false); + } + } +}