// SPDX-License-Identifier: MIT

use netlink_packet_core::{Emitable, Parseable};

use crate::{
    neighbour_table::{
        NeighbourTableAttribute, NeighbourTableConfig, NeighbourTableHeader,
        NeighbourTableMessage, NeighbourTableMessageBuffer,
        NeighbourTableParameter, NeighbourTableStats,
    },
    AddressFamily,
};

// There is no need to do ipv6 test as it is almost identical to ipv4 for
// neighbour_table.

// Wireshark nlmon capture of `examples/dump_neighbour_tables.rs`
#[test]
fn test_ipv4_neighbour_table() {
    let raw = vec![
        0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x61, 0x72, 0x70, 0x5f,
        0x63, 0x61, 0x63, 0x68, 0x65, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x06, 0x00,
        0x08, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
        0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x40, 0x03, 0x00,
        0x08, 0x00, 0x08, 0x00, 0x65, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0e, 0x00,
        0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x08, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0b, 0x00,
        0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x03, 0x00, 0x93, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x04, 0x00, 0x30, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x06, 0x00, 0x60, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x07, 0x00, 0x88, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x05, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x0c, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x0d, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x0f, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x13, 0x00, 0x88, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    ];

    let expected = NeighbourTableMessage {
        header: NeighbourTableHeader {
            family: AddressFamily::Inet,
        },
        attributes: vec![
            NeighbourTableAttribute::Name("arp_cache".to_string()),
            NeighbourTableAttribute::Parms(vec![
                NeighbourTableParameter::Ifindex(16),
                NeighbourTableParameter::ReferenceCount(1),
                NeighbourTableParameter::QueueLenbytes(212992),
                NeighbourTableParameter::QueueLen(101),
                NeighbourTableParameter::ProxyQlen(64),
                NeighbourTableParameter::AppProbes(0),
                NeighbourTableParameter::UcastProbes(3),
                NeighbourTableParameter::McastProbes(3),
                NeighbourTableParameter::McastReprobes(0),
                NeighbourTableParameter::ReachableTime(18067),
                NeighbourTableParameter::BaseReachableTime(30000),
                NeighbourTableParameter::GcStaletime(60000),
                NeighbourTableParameter::DelayProbeTime(5000),
                NeighbourTableParameter::RetransTime(1000),
                NeighbourTableParameter::AnycastDelay(1000),
                NeighbourTableParameter::ProxyDelay(800),
                NeighbourTableParameter::Locktime(1000),
                NeighbourTableParameter::IntervalProbeTimeMs(5000),
            ]),
        ],
    };

    assert_eq!(
        expected,
        NeighbourTableMessage::parse(&NeighbourTableMessageBuffer::new(&raw))
            .unwrap()
    );

    let mut buf = vec![0; expected.buffer_len()];

    expected.emit(&mut buf);

    assert_eq!(buf, raw);
}

// Wireshark nlmon capture of `examples/dump_neighbour_tables.rs`
#[test]
fn test_ipv4_neighbour_table_stats_config() {
    let raw = vec![
        0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x61, 0x72, 0x70, 0x5f,
        0x63, 0x61, 0x63, 0x68, 0x65, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00,
        0x30, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
        0x80, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00,
        0x08, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x24, 0x00, 0x05, 0x00,
        0x04, 0x00, 0x98, 0x01, 0x0c, 0x00, 0x00, 0x00, 0x3a, 0x02, 0xac, 0x02,
        0x6d, 0x66, 0x01, 0x00, 0xd5, 0x7e, 0xc0, 0xe4, 0x0f, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x07, 0x00,
        0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x3d, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x0c, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x44, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x06, 0x00, 0x08, 0x00, 0x02, 0x00,
        0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x40, 0x03, 0x00,
        0x08, 0x00, 0x08, 0x00, 0x65, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0e, 0x00,
        0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x08, 0x00, 0x0a, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0b, 0x00,
        0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x03, 0x00, 0xaa, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x04, 0x00, 0x30, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x06, 0x00, 0x60, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x07, 0x00, 0x88, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x05, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x0c, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x0d, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x0f, 0x00, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x0c, 0x00, 0x13, 0x00, 0x88, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    ];

    let expected = NeighbourTableMessage {
        header: NeighbourTableHeader {
            family: AddressFamily::Inet,
        },
        attributes: vec![
            NeighbourTableAttribute::Name("arp_cache".to_string()),
            NeighbourTableAttribute::GcInterval(30000),
            NeighbourTableAttribute::Threshold1(128),
            NeighbourTableAttribute::Threshold2(512),
            NeighbourTableAttribute::Threshold3(1024),
            NeighbourTableAttribute::Config(NeighbourTableConfig {
                key_len: 4,
                entry_size: 408,
                entries: 12,
                last_flush: 44827194,
                last_rand: 91757,
                hash_rand: 3837820629,
                hash_mask: 15,
                hash_chain_gc: 0,
                proxy_qlen: 0,
            }),
            NeighbourTableAttribute::Stats(NeighbourTableStats {
                allocs: 17,
                destroys: 5,
                hash_grows: 1,
                res_failed: 16,
                lookups: 15626,
                hits: 9228,
                multicast_probes_received: 0,
                unicast_probes_received: 0,
                periodic_gc_runs: 2884,
                forced_gc_runs: 0,
                table_fulls: 0,
            }),
            NeighbourTableAttribute::Parms(vec![
                NeighbourTableParameter::ReferenceCount(1),
                NeighbourTableParameter::QueueLenbytes(212992),
                NeighbourTableParameter::QueueLen(101),
                NeighbourTableParameter::ProxyQlen(64),
                NeighbourTableParameter::AppProbes(0),
                NeighbourTableParameter::UcastProbes(3),
                NeighbourTableParameter::McastProbes(3),
                NeighbourTableParameter::McastReprobes(0),
                NeighbourTableParameter::ReachableTime(38570),
                NeighbourTableParameter::BaseReachableTime(30000),
                NeighbourTableParameter::GcStaletime(60000),
                NeighbourTableParameter::DelayProbeTime(5000),
                NeighbourTableParameter::RetransTime(1000),
                NeighbourTableParameter::AnycastDelay(1000),
                NeighbourTableParameter::ProxyDelay(800),
                NeighbourTableParameter::Locktime(1000),
                NeighbourTableParameter::IntervalProbeTimeMs(5000),
            ]),
        ],
    };

    assert_eq!(
        expected,
        NeighbourTableMessage::parse(&NeighbourTableMessageBuffer::new(&raw))
            .unwrap()
    );

    let mut buf = vec![0; expected.buffer_len()];

    expected.emit(&mut buf);

    assert_eq!(buf, raw);
}
