spill 0.5.1

Modern torrent client
Documentation
use spill::protocol::bencode::{
    ErrorKind, Limits, MAX_DEPTH, Node, Value, decode, decode_prefix, encode,
};

#[test]
fn byte_strings_are_borrowed_and_binary_safe() {
    let input = b"3:\0\xffe";
    let node = decode(input, Limits::default()).unwrap();
    let Value::Bytes(bytes) = node.value() else {
        panic!("expected bytes")
    };
    assert_eq!(*bytes, &input[2..]);
    assert_eq!(bytes.as_ptr(), input[2..].as_ptr());
}

#[test]
fn input_and_string_budgets_have_exact_boundaries() {
    let limits = Limits {
        max_input_len: 5,
        max_string_len: 3,
        ..Limits::default()
    };
    assert!(decode(b"3:abc", limits).is_ok());
    assert_eq!(
        decode(b"3:abcd", limits).unwrap_err().kind,
        ErrorKind::InputLimit
    );
    assert_eq!(
        decode(b"4:abc", limits).unwrap_err().kind,
        ErrorKind::StringLimit
    );
    assert_eq!(
        decode(b"3:ab", limits).unwrap_err().kind,
        ErrorKind::UnexpectedEnd
    );
    assert_eq!(
        decode_prefix(b"i1eabc", limits).unwrap_err().kind,
        ErrorKind::InputLimit
    );
}

#[test]
fn node_budget_counts_keys_and_overwritten_values() {
    let limits = Limits {
        max_nodes: 5,
        ..Limits::default()
    };
    assert!(decode(b"d1:ai1e1:ai2ee", limits).is_ok());
    let limits = Limits {
        max_nodes: 4,
        ..limits
    };
    assert_eq!(
        decode(b"d1:ai1e1:ai2ee", limits).unwrap_err().kind,
        ErrorKind::NodeLimit
    );
    let limits = Limits {
        max_nodes: 0,
        ..limits
    };
    assert_eq!(
        decode(b"i0e", limits).unwrap_err().kind,
        ErrorKind::NodeLimit
    );
}

#[test]
fn container_depth_budget_and_hard_ceiling() {
    let limits = Limits {
        max_depth: 0,
        ..Limits::default()
    };
    assert!(decode(b"i1e", limits).is_ok());
    assert_eq!(
        decode(b"le", limits).unwrap_err().kind,
        ErrorKind::DepthLimit
    );
    let limits = Limits {
        max_depth: 1,
        ..limits
    };
    assert!(decode(b"li1ee", limits).is_ok());
    assert_eq!(
        decode(b"llee", limits).unwrap_err().kind,
        ErrorKind::DepthLimit
    );
    let at_limit = format!("{}0:{}", "l".repeat(MAX_DEPTH), "e".repeat(MAX_DEPTH));
    let node = decode(at_limit.as_bytes(), Limits::default()).unwrap();
    assert_eq!(
        encode(&node, Limits::default()).unwrap(),
        at_limit.as_bytes()
    );
    let too_deep = format!("l{at_limit}e");
    assert_eq!(
        decode(too_deep.as_bytes(), Limits::default())
            .unwrap_err()
            .kind,
        ErrorKind::DepthLimit
    );
    let bad_config = Limits {
        max_depth: MAX_DEPTH + 1,
        ..limits
    };
    assert_eq!(
        decode(b"i1e", bad_config).unwrap_err().kind,
        ErrorKind::InvalidLimits
    );
    assert_eq!(
        encode(&Node::new(Value::Integer(1)), bad_config)
            .unwrap_err()
            .kind,
        ErrorKind::InvalidLimits
    );
}

#[test]
fn encoder_budgets_apply_to_constructed_values() {
    let node = Node::new(Value::List(vec![Node::new(Value::Bytes(b"abc"))]));
    let limits = Limits {
        max_output_len: 7,
        ..Limits::default()
    };
    assert_eq!(encode(&node, limits).unwrap(), b"l3:abce");
    let limits = Limits {
        max_output_len: 6,
        ..limits
    };
    assert_eq!(
        encode(&node, limits).unwrap_err().kind,
        ErrorKind::OutputLimit
    );
    let limits = Limits {
        max_nodes: 1,
        ..Limits::default()
    };
    assert_eq!(
        encode(&node, limits).unwrap_err().kind,
        ErrorKind::NodeLimit
    );
    let limits = Limits {
        max_depth: 0,
        ..Limits::default()
    };
    assert_eq!(
        encode(&node, limits).unwrap_err().kind,
        ErrorKind::DepthLimit
    );
    let limits = Limits {
        max_string_len: 2,
        ..Limits::default()
    };
    assert_eq!(
        encode(&node, limits).unwrap_err().kind,
        ErrorKind::StringLimit
    );
    let limits = Limits {
        max_output_len: 0,
        ..Limits::default()
    };
    assert_eq!(
        encode(&node, limits).unwrap_err().kind,
        ErrorKind::OutputLimit
    );
}