use super::*;
use std::time::*;

#[test]
pub fn when_there_is_no_instruction_at_ip_then_end_the_program() {

    // Arrange
    
    const P1: [Option<Instruction>; 24] = [
        None; 24
    ];

    let memory = MemoryBuilder::new()
        .with_p1(P1)
        .with_ip(3)
        .build();

    let (sender, receiver) = mpsc::channel();

    let mut alu = DefaultAlu {
        memory: memory,
        system: sender
    };

    // Act
    
    let instruction = alu.read_instruction(3);
    let result = alu.process_instruction();
    let message = receiver.recv_timeout(Duration::from_secs(1));

    // Assert

    assert_eq!(None, instruction);
    assert_eq!(Ok(()), result);
    assert_eq!(3, alu.memory.ip);
    assert_eq!(Ok(Message::ProgramEnded), message);
}

#[test]
pub fn when_executiong_a_stop_instruction_then_stop_the_program() {

    // Arrange
    
    const P1: [Option<Instruction>; 24] = [
        Some(Instruction::Stop); 24
    ];

    let memory = MemoryBuilder::new()
        .with_p1(P1)
        .with_ip(3)
        .build();

    let (sender, receiver) = mpsc::channel();

    let mut alu = DefaultAlu {
        memory: memory,
        system: sender
    };

    // Act
    
    let instruction = alu.read_instruction(3);
    let result = alu.process_instruction();
    let message = receiver.recv_timeout(Duration::from_secs(1));

    // Assert

    assert_eq!(Some(Instruction::Stop), instruction);
    assert_eq!(Ok(()), result);
    assert_eq!(3, alu.memory.ip);
    assert_eq!(Ok(Message::ProgramStopped), message);
}

#[test]
pub fn run_the_instruction_at_the_ip() {

    // Arrange
    
    const P1: [Option<Instruction>; 24] = [
        Some(Instruction::Print(Operand::A)),
        None, None, None, None, None, None, None, None, None, None,
        None, None, None, None, None, None, None, None, None, None,
        None, None, None
    ];

    let memory = MemoryBuilder::new()
        .with_p1(P1)
        .with_a(Decimal::new(123, 2))
        .with_ip(0)
        .build();

    let (sender, receiver) = mpsc::channel();

    let mut alu = DefaultAlu {
        memory: memory,
        system: sender
    };

    // Act
    
    let instruction = alu.read_instruction(0);
    let result = alu.process_instruction();
    let msg = receiver.recv_timeout(std::time::Duration::from_secs(1));

    // Assert

    assert_eq!(Some(Instruction::Print(Operand::A)), instruction);
    assert_eq!(Ok(()), result);
    assert_eq!(1, alu.memory.ip);
    assert_eq!(Ok(Message::PrintLine("1.23 A\u{20df}".to_string())), msg);
}

