Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/edda

crates/gunnar-pktline/tests/encode.rs

//! Encoder tests, **literal bytes only**.
//!
//! Every assertion here compares against a hand-written byte string, never
//! against the output of this crate's own decoder. A codec checked solely by
//! round-tripping agrees with itself by construction: shift the length by four
//! in both halves and every round-trip still passes while no git in the world
//! can read a byte of it. The literals below are the only thing in the crate
//! that is anchored to the protocol rather than to the implementation.

use gunnar_pktline::*;

fn enc(f: impl FnOnce(&mut Vec<u8>) -> Result<()>) -> Vec<u8> {
    let mut out = Vec::new();
    f(&mut out).expect("encode failed");
    out
}

#[test]
fn write_data_emits_length_including_the_header() {
    assert_eq!(enc(|o| write_data(o, b"hi")), b"0006hi".to_vec());
    assert_eq!(enc(|o| write_data(o, b"a")), b"0005a".to_vec());
    assert_eq!(enc(|o| write_data(o, b"abcdef")), b"000aabcdef".to_vec());
}

#[test]
fn empty_data_packet_is_0004_and_is_not_a_flush() {
    // 0000 and 0004 are different packets. Collapsing them loses section
    // boundaries in protocol v2.
    assert_eq!(enc(|o| write_data(o, b"")), b"0004".to_vec());
    assert_ne!(enc(|o| write_data(o, b"")), enc(write_flush));
}

#[test]
fn control_packets_are_exact_four_byte_literals() {
    assert_eq!(enc(write_flush), b"0000".to_vec());
    assert_eq!(enc(write_delim), b"0001".to_vec());
    assert_eq!(enc(write_response_end), b"0002".to_vec());
}

#[test]
fn a_real_ref_advertisement_line_is_byte_exact() {
    // 40 hex + space + 15 + newline = 57 payload, +4 header = 61 = 0x3d.
    let line = b"0000000000000000000000000000000000000000 refs/heads/main\n";
    assert_eq!(line.len(), 57);
    let got = enc(|o| write_data(o, line));
    assert_eq!(
        got,
        b"003d0000000000000000000000000000000000000000 refs/heads/main\n".to_vec()
    );
    assert_eq!(got.len(), 61);
}

#[test]
fn write_data_never_touches_the_payload() {
    // Binary is legal on the wire; an encoder that "helpfully" newline-terminates
    // would corrupt every packfile byte it framed.
    let payload = [0x00u8, 0xff, 0x0a, 0x50, 0x41, 0x43, 0x4b];
    let mut expected = b"000b".to_vec();
    expected.extend_from_slice(&payload);
    assert_eq!(enc(|o| write_data(o, &payload)), expected);
}

#[test]
fn write_text_appends_exactly_one_newline_when_absent() {
    assert_eq!(enc(|o| write_text(o, b"hi")), b"0007hi\n".to_vec());
    assert_eq!(enc(|o| write_text(o, b"")), b"0005\n".to_vec());
}

#[test]
fn write_text_is_idempotent_on_an_already_terminated_line() {
    assert_eq!(enc(|o| write_text(o, b"hi\n")), b"0007hi\n".to_vec());
    assert_eq!(
        enc(|o| write_text(o, b"hi\n")),
        enc(|o| write_text(o, b"hi"))
    );
    // A payload that legitimately ends in a blank line keeps both newlines.
    assert_eq!(enc(|o| write_text(o, b"hi\n\n")), b"0008hi\n\n".to_vec());
}

#[test]
fn length_header_is_lowercase_and_zero_padded() {
    // 167 payload bytes → 171 total → 0x00ab. Catches both a `{:x}` without the
    // zero pad and an uppercase `{:X}`; either desyncs a peer.
    let got = enc(|o| write_data(o, &[b'x'; 167]));
    assert_eq!(&got[..4], b"00ab");
    assert_eq!(got.len(), 171);
}

#[test]
fn max_payload_is_exactly_the_one_that_fits() {
    let got = enc(|o| write_data(o, &vec![b'x'; MAX_PAYLOAD]));
    assert_eq!(&got[..4], b"fff0");
    assert_eq!(got.len(), MAX_LINE);
    assert_eq!(MAX_LINE, 65520);
}

#[test]
fn one_byte_over_max_payload_is_rejected_not_truncated() {
    let mut out = Vec::new();
    let err = write_data(&mut out, &vec![b'x'; MAX_PAYLOAD + 1]).unwrap_err();
    assert!(
        matches!(err, Error::TooLong(n) if n == MAX_PAYLOAD + 1),
        "{err:?}"
    );
    // Nothing may be emitted for a rejected packet. A half-written frame is
    // worse than no frame.
    assert!(out.is_empty());
}

#[test]
fn write_text_counts_the_newline_it_is_about_to_add() {
    // MAX_PAYLOAD - 1 bytes plus the appended newline is exactly the limit.
    let ok = enc(|o| write_text(o, &vec![b'x'; MAX_PAYLOAD - 1]));
    assert_eq!(&ok[..4], b"fff0");
    assert_eq!(ok.len(), MAX_LINE);
    // MAX_PAYLOAD bytes of text would become MAX_PAYLOAD + 1 once terminated.
    let mut out = Vec::new();
    let err = write_text(&mut out, &vec![b'x'; MAX_PAYLOAD]).unwrap_err();
    assert!(
        matches!(err, Error::TooLong(n) if n == MAX_PAYLOAD + 1),
        "{err:?}"
    );
    assert!(out.is_empty());
}

#[test]
fn a_whole_v2_command_section_is_byte_exact() {
    // The shape gunnar's upload-pack actually writes: command, delim, args, flush.
    let got = enc(|o| {
        write_text(o, b"command=ls-refs")?;
        write_delim(o)?;
        write_text(o, b"peel")?;
        write_text(o, b"symrefs")?;
        write_flush(o)
    });
    assert_eq!(
        got,
        b"0014command=ls-refs\n00010009peel\n000csymrefs\n0000".to_vec()
    );
}

#[test]
fn write_packet_matches_the_dedicated_writers() {
    assert_eq!(
        enc(|o| write_packet(o, &Packet::Data(b"hi".to_vec()))),
        b"0006hi".to_vec()
    );
    assert_eq!(enc(|o| write_packet(o, &Packet::Flush)), b"0000".to_vec());
    assert_eq!(enc(|o| write_packet(o, &Packet::Delim)), b"0001".to_vec());
    assert_eq!(
        enc(|o| write_packet(o, &Packet::ResponseEnd)),
        b"0002".to_vec()
    );
}

#[test]
fn constants_are_the_protocol_numbers() {
    // A renumber here would be silently absorbed by every other test in the
    // suite, since they all read the constants back.
    assert_eq!(MAX_PAYLOAD, 65516);
    assert_eq!(BAND_PACK, 1);
    assert_eq!(BAND_PROGRESS, 2);
    assert_eq!(BAND_ERROR, 3);
    assert_eq!(SIDEBAND_CHUNK, 65515);
}