ibapi 4.0.0

A Rust implementation of the Interactive Brokers TWS API, providing a reliable and user friendly interface for TWS and IB Gateway. Designed with a focus on simplicity and performance.
Documentation
use super::*;
use crate::common::test_utils::helpers::assert_rejects_text_framing;
use crate::messages::IncomingMessages;

#[test]
fn test_decode_scanner_data_proto() {
    use prost::Message;

    let proto_msg = crate::proto::ScannerData {
        req_id: Some(1),
        scanner_data_element: vec![
            crate::proto::ScannerDataElement {
                rank: Some(0),
                contract: Some(crate::proto::Contract {
                    con_id: Some(265598),
                    symbol: Some("AAPL".into()),
                    sec_type: Some("STK".into()),
                    ..Default::default()
                }),
                market_name: Some("NMS".into()),
                distance: Some("1.5".into()),
                benchmark: Some("".into()),
                projection: Some("".into()),
                combo_key: Some("".into()),
            },
            crate::proto::ScannerDataElement {
                rank: Some(1),
                contract: Some(crate::proto::Contract {
                    con_id: Some(76792991),
                    symbol: Some("TSLA".into()),
                    sec_type: Some("STK".into()),
                    ..Default::default()
                }),
                market_name: Some("NMS".into()),
                distance: None,
                benchmark: None,
                projection: None,
                combo_key: None,
            },
        ],
    };

    let mut bytes = Vec::new();
    proto_msg.encode(&mut bytes).unwrap();

    let results = decode_scanner_data_proto(&bytes).unwrap();
    assert_eq!(results.len(), 2);
    assert_eq!(results[0].rank, 0);
    assert_eq!(results[0].contract_details.contract.contract_id, 265598);
    assert_eq!(results[0].contract_details.market_name, "NMS");
}

#[test]
fn test_decode_scanner_parameters_proto() {
    let xml = "<ScanParameterResponse><ScanTypeList /></ScanParameterResponse>";
    let proto_msg = crate::proto::ScannerParameters { xml: Some(xml.into()) };
    let result = decode_scanner_parameters_proto(proto_msg).unwrap();
    assert_eq!(result, xml);
}

#[test]
fn test_decode_scanner_parameters_proto_empty() {
    let proto_msg = crate::proto::ScannerParameters { xml: None };
    let result = decode_scanner_parameters_proto(proto_msg).unwrap();
    assert_eq!(result, "");
}

#[test]
fn test_decode_scanner_data_rejects_text_framing() {
    // Servers ≥ the connection floor always emit ScannerData in proto.
    // Text-framed arrival raises `UnexpectedWireFormat` — the message was
    // addressed to this decoder, so it is not skippable. See
    // docs/rules/wire/proto-only-decoding.md.
    assert_rejects_text_framing(
        IncomingMessages::ScannerData,
        "20\03\09000\01\00\0265598\0AAPL\0STK\0\00\0\0SMART\0USD\0AAPL\0NMS\0NMS\0\0\0\0\0",
        decode_scanner_data,
    );
}