//! Тесты на правильность генерирования машинного кода.
use crate::codegen_tests::helper::compile;

fn assert_code(source: &str, expected: &[u8]) {
    let output =
        compile(source).unwrap_or_else(|err| panic!("compile failed for `{source}`: {err}"));
    assert_eq!(output.code, expected, "wrong bytes for `{source}`");
    assert!(
        output.label_offsets.is_empty(),
        "expected no labels for `{source}`"
    );
}

#[test]
fn push_rax() {
    assert_code("push rax", &[0x50]);
}

#[test]
fn push_rcx() {
    assert_code("push rcx", &[0x51]);
}

#[test]
fn push_rdx() {
    assert_code("push rdx", &[0x52]);
}

#[test]
fn push_rbx() {
    assert_code("push rbx", &[0x53]);
}

#[test]
fn push_rsp() {
    assert_code("push rsp", &[0x54]);
}

#[test]
fn push_rbp() {
    assert_code("push rbp", &[0x55]);
}

#[test]
fn push_rsi() {
    assert_code("push rsi", &[0x56]);
}

#[test]
fn push_rdi() {
    assert_code("push rdi", &[0x57]);
}

#[test]
fn push_r8() {
    assert_code("push r8", &[0x41, 0x50]);
}

#[test]
fn push_r9() {
    assert_code("push r9", &[0x41, 0x51]);
}

#[test]
fn push_r10() {
    assert_code("push r10", &[0x41, 0x52]);
}

#[test]
fn push_r11() {
    assert_code("push r11", &[0x41, 0x53]);
}

#[test]
fn push_r12() {
    assert_code("push r12", &[0x41, 0x54]);
}

#[test]
fn push_r13() {
    assert_code("push r13", &[0x41, 0x55]);
}

#[test]
fn push_r14() {
    assert_code("push r14", &[0x41, 0x56]);
}

#[test]
fn push_r15() {
    assert_code("push r15", &[0x41, 0x57]);
}

#[test]
fn pop_rax() {
    assert_code("pop rax", &[0x58]);
}

#[test]
fn pop_rcx() {
    assert_code("pop rcx", &[0x59]);
}

#[test]
fn pop_rdx() {
    assert_code("pop rdx", &[0x5A]);
}

#[test]
fn pop_rbx() {
    assert_code("pop rbx", &[0x5B]);
}

#[test]
fn pop_rsp() {
    assert_code("pop rsp", &[0x5C]);
}

#[test]
fn pop_rbp() {
    assert_code("pop rbp", &[0x5D]);
}

#[test]
fn pop_rsi() {
    assert_code("pop rsi", &[0x5E]);
}

#[test]
fn pop_rdi() {
    assert_code("pop rdi", &[0x5F]);
}

#[test]
fn pop_r8() {
    assert_code("pop r8", &[0x41, 0x58]);
}

#[test]
fn pop_r9() {
    assert_code("pop r9", &[0x41, 0x59]);
}

#[test]
fn pop_r10() {
    assert_code("pop r10", &[0x41, 0x5A]);
}

#[test]
fn pop_r11() {
    assert_code("pop r11", &[0x41, 0x5B]);
}

#[test]
fn pop_r12() {
    assert_code("pop r12", &[0x41, 0x5C]);
}

#[test]
fn pop_r13() {
    assert_code("pop r13", &[0x41, 0x5D]);
}

#[test]
fn pop_r14() {
    assert_code("pop r14", &[0x41, 0x5E]);
}

#[test]
fn pop_r15() {
    assert_code("pop r15", &[0x41, 0x5F]);
}

#[test]
fn mov_rax_rax() {
    assert_code("mov rax, rax", &[0x48, 0x89, 0xC0]);
}

#[test]
fn mov_rcx_rcx() {
    assert_code("mov rcx, rcx", &[0x48, 0x89, 0xC9]);
}

#[test]
fn mov_rdx_rdx() {
    assert_code("mov rdx, rdx", &[0x48, 0x89, 0xD2]);
}

#[test]
fn mov_rbx_rbx() {
    assert_code("mov rbx, rbx", &[0x48, 0x89, 0xDB]);
}

#[test]
fn mov_rsp_rsp() {
    assert_code("mov rsp, rsp", &[0x48, 0x89, 0xE4]);
}

#[test]
fn mov_rbp_rbp() {
    assert_code("mov rbp, rbp", &[0x48, 0x89, 0xED]);
}

#[test]
fn mov_rsi_rsi() {
    assert_code("mov rsi, rsi", &[0x48, 0x89, 0xF6]);
}

#[test]
fn mov_rdi_rdi() {
    assert_code("mov rdi, rdi", &[0x48, 0x89, 0xFF]);
}

#[test]
fn mov_r8_r8() {
    assert_code("mov r8, r8", &[0x4D, 0x89, 0xC0]);
}

#[test]
fn mov_r9_r9() {
    assert_code("mov r9, r9", &[0x4D, 0x89, 0xC9]);
}

#[test]
fn mov_r10_r10() {
    assert_code("mov r10, r10", &[0x4D, 0x89, 0xD2]);
}

#[test]
fn mov_r11_r11() {
    assert_code("mov r11, r11", &[0x4D, 0x89, 0xDB]);
}

#[test]
fn mov_r12_r12() {
    assert_code("mov r12, r12", &[0x4D, 0x89, 0xE4]);
}

#[test]
fn mov_r13_r13() {
    assert_code("mov r13, r13", &[0x4D, 0x89, 0xED]);
}

#[test]
fn mov_r14_r14() {
    assert_code("mov r14, r14", &[0x4D, 0x89, 0xF6]);
}

#[test]
fn mov_r15_r15() {
    assert_code("mov r15, r15", &[0x4D, 0x89, 0xFF]);
}

#[test]
fn add_rax_rax() {
    assert_code("add rax, rax", &[0x48, 0x01, 0xC0]);
}

#[test]
fn add_rcx_rcx() {
    assert_code("add rcx, rcx", &[0x48, 0x01, 0xC9]);
}

#[test]
fn add_rdx_rdx() {
    assert_code("add rdx, rdx", &[0x48, 0x01, 0xD2]);
}

#[test]
fn add_rbx_rbx() {
    assert_code("add rbx, rbx", &[0x48, 0x01, 0xDB]);
}

#[test]
fn add_rsp_rsp() {
    assert_code("add rsp, rsp", &[0x48, 0x01, 0xE4]);
}

#[test]
fn add_rbp_rbp() {
    assert_code("add rbp, rbp", &[0x48, 0x01, 0xED]);
}

#[test]
fn add_rsi_rsi() {
    assert_code("add rsi, rsi", &[0x48, 0x01, 0xF6]);
}

#[test]
fn add_rdi_rdi() {
    assert_code("add rdi, rdi", &[0x48, 0x01, 0xFF]);
}

#[test]
fn add_r8_r8() {
    assert_code("add r8, r8", &[0x4D, 0x01, 0xC0]);
}

#[test]
fn add_r9_r9() {
    assert_code("add r9, r9", &[0x4D, 0x01, 0xC9]);
}

#[test]
fn add_r10_r10() {
    assert_code("add r10, r10", &[0x4D, 0x01, 0xD2]);
}

#[test]
fn add_r11_r11() {
    assert_code("add r11, r11", &[0x4D, 0x01, 0xDB]);
}

#[test]
fn add_r12_r12() {
    assert_code("add r12, r12", &[0x4D, 0x01, 0xE4]);
}

#[test]
fn add_r13_r13() {
    assert_code("add r13, r13", &[0x4D, 0x01, 0xED]);
}

#[test]
fn add_r14_r14() {
    assert_code("add r14, r14", &[0x4D, 0x01, 0xF6]);
}

#[test]
fn add_r15_r15() {
    assert_code("add r15, r15", &[0x4D, 0x01, 0xFF]);
}

#[test]
fn sub_rax_rax() {
    assert_code("sub rax, rax", &[0x48, 0x29, 0xC0]);
}

#[test]
fn sub_rcx_rcx() {
    assert_code("sub rcx, rcx", &[0x48, 0x29, 0xC9]);
}

#[test]
fn sub_rdx_rdx() {
    assert_code("sub rdx, rdx", &[0x48, 0x29, 0xD2]);
}

#[test]
fn sub_rbx_rbx() {
    assert_code("sub rbx, rbx", &[0x48, 0x29, 0xDB]);
}

#[test]
fn sub_rsp_rsp() {
    assert_code("sub rsp, rsp", &[0x48, 0x29, 0xE4]);
}

#[test]
fn sub_rbp_rbp() {
    assert_code("sub rbp, rbp", &[0x48, 0x29, 0xED]);
}

#[test]
fn sub_rsi_rsi() {
    assert_code("sub rsi, rsi", &[0x48, 0x29, 0xF6]);
}

#[test]
fn sub_rdi_rdi() {
    assert_code("sub rdi, rdi", &[0x48, 0x29, 0xFF]);
}

#[test]
fn sub_r8_r8() {
    assert_code("sub r8, r8", &[0x4D, 0x29, 0xC0]);
}

#[test]
fn sub_r9_r9() {
    assert_code("sub r9, r9", &[0x4D, 0x29, 0xC9]);
}

#[test]
fn sub_r10_r10() {
    assert_code("sub r10, r10", &[0x4D, 0x29, 0xD2]);
}

#[test]
fn sub_r11_r11() {
    assert_code("sub r11, r11", &[0x4D, 0x29, 0xDB]);
}

#[test]
fn sub_r12_r12() {
    assert_code("sub r12, r12", &[0x4D, 0x29, 0xE4]);
}

#[test]
fn sub_r13_r13() {
    assert_code("sub r13, r13", &[0x4D, 0x29, 0xED]);
}

#[test]
fn sub_r14_r14() {
    assert_code("sub r14, r14", &[0x4D, 0x29, 0xF6]);
}

#[test]
fn sub_r15_r15() {
    assert_code("sub r15, r15", &[0x4D, 0x29, 0xFF]);
}

#[test]
fn xor_rax_rax() {
    assert_code("xor rax, rax", &[0x48, 0x31, 0xC0]);
}

#[test]
fn xor_rcx_rcx() {
    assert_code("xor rcx, rcx", &[0x48, 0x31, 0xC9]);
}

#[test]
fn xor_rdx_rdx() {
    assert_code("xor rdx, rdx", &[0x48, 0x31, 0xD2]);
}

#[test]
fn xor_rbx_rbx() {
    assert_code("xor rbx, rbx", &[0x48, 0x31, 0xDB]);
}

#[test]
fn xor_rsp_rsp() {
    assert_code("xor rsp, rsp", &[0x48, 0x31, 0xE4]);
}

#[test]
fn xor_rbp_rbp() {
    assert_code("xor rbp, rbp", &[0x48, 0x31, 0xED]);
}

#[test]
fn xor_rsi_rsi() {
    assert_code("xor rsi, rsi", &[0x48, 0x31, 0xF6]);
}

#[test]
fn xor_rdi_rdi() {
    assert_code("xor rdi, rdi", &[0x48, 0x31, 0xFF]);
}

#[test]
fn xor_r8_r8() {
    assert_code("xor r8, r8", &[0x4D, 0x31, 0xC0]);
}

#[test]
fn xor_r9_r9() {
    assert_code("xor r9, r9", &[0x4D, 0x31, 0xC9]);
}

#[test]
fn xor_r10_r10() {
    assert_code("xor r10, r10", &[0x4D, 0x31, 0xD2]);
}

#[test]
fn xor_r11_r11() {
    assert_code("xor r11, r11", &[0x4D, 0x31, 0xDB]);
}

#[test]
fn xor_r12_r12() {
    assert_code("xor r12, r12", &[0x4D, 0x31, 0xE4]);
}

#[test]
fn xor_r13_r13() {
    assert_code("xor r13, r13", &[0x4D, 0x31, 0xED]);
}

#[test]
fn xor_r14_r14() {
    assert_code("xor r14, r14", &[0x4D, 0x31, 0xF6]);
}

#[test]
fn xor_r15_r15() {
    assert_code("xor r15, r15", &[0x4D, 0x31, 0xFF]);
}

#[test]
fn nop() {
    assert_code("nop", &[0x90]);
}

#[test]
fn ret() {
    assert_code("ret", &[0xC3]);
}

#[test]
fn syscall() {
    assert_code("syscall", &[0x0F, 0x05]);
}

#[test]
fn nop_ret() {
    assert_code("nop\nret", &[0x90, 0xC3]);
}
