use super::*;
use crate::alu::TestAluBuilder;
use std::thread;

#[test]
pub fn perform_an_addition_from_user_input() {
    // Arrange

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

    let alu = TestAluBuilder::new(sender.clone())
        .build();

    let mut component = AluComponent::new(alu, sender.clone());
    let component_sender = component.link.component_sender.clone();

    // Act

    let handle = thread::spawn(move || {
        component.run();
        return component.alu;
    });

    component_sender.send(Message::SystemStatusChanged(SystemStatus::Ready)).unwrap();
    component_sender.send(Message::KeyPressed(Key::Add)).unwrap();
    component_sender.send(Message::Halt).unwrap();

    let alu = handle.join().expect("The component should halt");

    // Assert

    assert_eq!(1, alu.log.len(), "One operation should have been logged");
    assert_eq!("add(M)", alu.log[0], "Should record an ADD(M) operation");
    assert_eq!(0, alu.ip, "IP should be unchanged");
}

#[test]
pub fn perform_an_addition_from_program() {
    // Arrange

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

    let alu = TestAluBuilder::new(sender.clone())
        .instr(0, Instruction::Label(JumpDestination::AV))
        .instr(1, Instruction::Add(Register::M))
        .build();

    let mut component = AluComponent::new(alu, sender.clone());
    let component_sender = component.link.component_sender.clone();

    // Act

    let handle = thread::spawn(move || {
        component.run();
        return component.alu;
    });

    component_sender.send(Message::SystemStatusChanged(SystemStatus::Ready)).unwrap();
    component_sender.send(Message::KeyPressed(Key::V)).unwrap();
    component_sender.send(Message::Halt).unwrap();

    let alu = handle.join().expect("The component should halt");

    // Assert

    assert_eq!(1, alu.log.len(), "One operation should have been logged");
    assert_eq!("add(M)", alu.log[0], "Should record an ADD(M) operation");
    assert_eq!(2, alu.ip, "IP should be updated to 2");
}
