ibapi 5.4.0

An unofficial Rust client for the Interactive Brokers TWS API: market data, orders, and account data, with async (Tokio) and blocking clients for TWS and IB Gateway.
Documentation
use super::helpers::*;
use crate::messages::{encode_protobuf_message, OutgoingMessages};
use crate::server_versions;

#[test]
fn create_test_client_works() {
    let (client, message_bus) = create_test_client();
    assert_eq!(client.server_version(), server_versions::SIZE_RULES);
    assert!(message_bus.request_messages.read().unwrap().is_empty());
    assert!(message_bus.ordered_responses.is_empty());
}

#[test]
fn create_test_client_with_version_works() {
    let custom_version = 150;
    let (client, message_bus) = create_test_client_with_version(custom_version);
    assert_eq!(client.server_version(), custom_version);
    assert!(message_bus.request_messages.read().unwrap().is_empty());
    assert!(message_bus.ordered_responses.is_empty());
}

#[test]
fn assert_request_msg_id_works() {
    let (_client, message_bus) = create_test_client();

    {
        let mut request_messages = message_bus.request_messages.write().unwrap();
        request_messages.push(encode_protobuf_message(OutgoingMessages::RequestAccountSummary as i32, &[]));
    }

    assert_request_msg_id(&message_bus, 0, OutgoingMessages::RequestAccountSummary);
}

#[test]
fn request_message_count_works() {
    let (_client, message_bus) = create_test_client();

    assert_eq!(request_message_count(&message_bus), 0);

    {
        let mut request_messages = message_bus.request_messages.write().unwrap();
        request_messages.push(encode_protobuf_message(1, &[]));
        request_messages.push(encode_protobuf_message(2, &[]));
    }

    assert_eq!(request_message_count(&message_bus), 2);
}

#[test]
fn constants() {
    assert_eq!(TEST_ACCOUNT, "DU1234567");
    assert_eq!(TEST_CONTRACT_ID, 1001);
    assert_eq!(TEST_ORDER_ID, 5001);
    assert_eq!(TEST_TICKER_ID, 100);
}

#[test]
fn assert_request_proto_matches_expected_body() {
    use crate::proto::ManagedAccountsRequest;
    use prost::Message;

    let (_client, message_bus) = create_test_client();

    let expected = ManagedAccountsRequest::default();
    let mut body = Vec::new();
    expected.encode(&mut body).unwrap();

    {
        let mut request_messages = message_bus.request_messages.write().unwrap();
        request_messages.push(encode_protobuf_message(OutgoingMessages::RequestManagedAccounts as i32, &body));
    }

    assert_request_proto(&message_bus, 0, OutgoingMessages::RequestManagedAccounts, &expected);
}

#[test]
fn assert_request_helper_resolves_msg_id_from_builder() {
    use crate::testdata::builders::{positions::request_positions_multi, RequestEncoder};

    let (_client, message_bus) = create_test_client();

    let builder = request_positions_multi().account("DU9999999").model_code("TARGET2024");

    {
        let mut request_messages = message_bus.request_messages.write().unwrap();
        request_messages.push(builder.encode_request());
    }

    assert_request(&message_bus, 0, &builder);
}

#[test]
#[should_panic(expected = "request 0 body mismatch")]
fn assert_request_helper_panics_on_body_mismatch() {
    use crate::testdata::builders::{positions::request_positions_multi, RequestEncoder};

    let (_client, message_bus) = create_test_client();

    let on_wire = request_positions_multi().account("DU0000001");
    {
        let mut request_messages = message_bus.request_messages.write().unwrap();
        request_messages.push(on_wire.encode_request());
    }

    let expected = request_positions_multi().account("DU0000002");
    assert_request(&message_bus, 0, &expected);
}

#[test]
#[should_panic(expected = "Expected at least 2 request messages, got 0")]
fn assert_request_msg_id_panics_on_short_buffer() {
    let (_client, message_bus) = create_test_client();
    assert_request_msg_id(&message_bus, 1, OutgoingMessages::RequestAccountSummary);
}

#[test]
fn assert_tws_error_message_matches_code_and_substring() {
    let err = tws_error_notice(10089, "not subscribed to market data");
    assert_tws_error_message(err, 10089, "not subscribed");
}

#[test]
#[should_panic(expected = "expected Error::Notice(code=10089)")]
fn assert_tws_error_message_panics_on_wrong_variant() {
    let err = crate::Error::Simple("nope".to_string());
    assert_tws_error_message(err, 10089, "not subscribed");
}

#[test]
#[should_panic(expected = "wrong error code")]
fn assert_tws_error_message_panics_on_wrong_code() {
    let err = tws_error_notice(1, "not subscribed");
    assert_tws_error_message(err, 10089, "not subscribed");
}

#[test]
#[should_panic(expected = "does not contain")]
fn assert_tws_error_message_panics_on_missing_substring() {
    let err = tws_error_notice(10089, "other text");
    assert_tws_error_message(err, 10089, "not subscribed");
}

#[test]
#[should_panic(expected = "request 0 body mismatch")]
fn assert_request_proto_panics_on_body_mismatch() {
    use crate::proto::AccountSummaryRequest;
    use prost::Message;

    let (_client, message_bus) = create_test_client();

    let on_wire = AccountSummaryRequest {
        req_id: Some(7),
        ..Default::default()
    };
    let mut body = Vec::new();
    on_wire.encode(&mut body).unwrap();

    {
        let mut request_messages = message_bus.request_messages.write().unwrap();
        request_messages.push(encode_protobuf_message(OutgoingMessages::RequestAccountSummary as i32, &body));
    }

    let expected = AccountSummaryRequest {
        req_id: Some(99),
        ..Default::default()
    };
    assert_request_proto(&message_bus, 0, OutgoingMessages::RequestAccountSummary, &expected);
}

#[test]
fn text_response_translates_pipes_to_nul() {
    let mut message = text_response("1|9001|payload");
    assert_eq!(message.next_string().unwrap(), "1");
    assert_eq!(message.next_string().unwrap(), "9001");
    assert_eq!(message.next_string().unwrap(), "payload");
}