use crate::prelude::*;

#[test]
fn test_encode_nop() {
    let no_reg = Register::Null as u32;
    let no_op = u32::from(Instruction::Nop.opcode());

    let expected = (no_op << 26) | (no_reg << 21) | (no_reg << 16) | (no_reg << 11);
    let got = Instruction::Nop.encode();

    assert_eq!(expected, got);
}

#[test]
fn test_encode_mov() {
    let rg0 = Register::Rg0 as u32;
    let rg1 = Register::Rg1 as u32;
    let no_reg = Register::Null as u32;

    let instruction = Instruction::Mov(RTypeArgs::new(
        Some(Register::Rg0),
        None,
        Some(Register::Rg1),
        None,
    ));
    let mov = u32::from(instruction.opcode());

    let expected = (mov << 26) | (rg0 << 21) | (no_reg << 16) | (rg1 << 11);
    let got = instruction.encode();

    assert_eq!(expected, got);
}

#[test]
fn test_encode_load_byte() {
    let rg0 = Register::Rg0 as u32;
    let rg1 = Register::Rg1 as u32;
    let immediate = 100;

    let instruction = Instruction::LoadByte(ITypeArgs::new(
        immediate,
        Some(Register::Rg0),
        Some(Register::Rg1),
    ));
    let load_byte = u32::from(instruction.opcode());

    let expected = (load_byte << 26) | (rg0 << 21) | (rg1 << 16) | u32::from(immediate);
    let got = instruction.encode();

    assert_eq!(expected, got);
}

#[test]
fn test_encode_shift_left_shamt() {
    let rg0 = Register::Rg0 as u32;
    let no_reg = Register::Null as u32;

    let shift_amount = 5;

    let instruction = Instruction::ShiftLeft(RTypeArgs::new(
        Some(Register::Rg0),
        None,
        None,
        Some(shift_amount),
    ));
    let shift_left = u32::from(instruction.opcode());

    let expected = (shift_left << 26)
        | (rg0 << 21)
        | (no_reg << 16)
        | (no_reg << 11)
        | (u32::from(shift_amount) << 6);

    let got = instruction.encode();

    assert_eq!(expected, got);
}

#[test]
fn test_encode_shift_left_reg() {
    let rg0 = Register::Rg0 as u32;
    let rg1 = Register::Rg1 as u32;
    let no_reg = Register::Null as u32;

    let instruction = Instruction::ShiftLeft(RTypeArgs::new(
        Some(Register::Rg0),
        Some(Register::Rg1),
        None,
        None,
    ));
    let shift_left = u32::from(instruction.opcode());

    let expected = (shift_left << 26) | (rg0 << 21) | (rg1 << 16) | (no_reg << 11);

    let got = instruction.encode();

    assert_eq!(expected, got);
}
