# Testing Patterns

This document describes the testing patterns and infrastructure used in the rust-ibapi crate, with a focus on the MockGateway pattern for integration testing.

## Testing Strategy

```mermaid
graph LR
    Change[Code Change]
    
    subgraph "Test Both Modes"
        TestSync[cargo test<br/>--features sync]
        TestAsync[cargo test<br/>--features async]
    end
    
    subgraph "Quality Checks"
        ClippySync[cargo clippy<br/>--features sync]
        ClippyAsync[cargo clippy<br/>--features async]
        Format[cargo fmt]
    end
    
    subgraph "Test Types"
        Unit[Unit Tests<br/>Individual functions]
        Integration[Integration Tests<br/>API workflows]
        Mock[MockGateway Tests<br/>Protocol verification]
    end
    
    Change --> TestSync
    Change --> TestAsync
    TestSync --> ClippySync
    TestAsync --> ClippyAsync
    ClippySync --> Format
    ClippyAsync --> Format
    
    TestSync --> Unit
    TestSync --> Integration
    TestSync --> Mock
    
    TestAsync --> Unit
    TestAsync --> Integration
    TestAsync --> Mock
    
    Format --> PR[Pull Request ✓]
    
    style Change fill:#ffd54f
    style PR fill:#aed581
```

## MockGateway Integration Testing Pattern

The MockGateway pattern provides a robust framework for testing Client methods without requiring a real IB Gateway/TWS connection. This pattern is implemented in `src/client/common.rs` and ensures consistent, reliable testing across both sync and async implementations.

### Architecture Overview

```mermaid
graph LR
    subgraph "Test Environment"
        Client[Client<br/>Under Test]
        MockGateway[MockGateway<br/>Simulated Server]
        TestData[Test Data<br/>Fixtures]
    end
    
    subgraph "Verification"
        Requests[Captured<br/>Requests]
        Responses[Expected<br/>Responses]
        Assertions[Test<br/>Assertions]
    end
    
    Client <-->|TCP Socket| MockGateway
    TestData -->|Provides| MockGateway
    MockGateway -->|Records| Requests
    MockGateway -->|Sends| Responses
    Requests --> Assertions
    Responses --> Assertions
    
    style Client fill:#bbdefb
    style MockGateway fill:#c5e1a5
    style Assertions fill:#ffccbc
```

### Key Components

1. **MockGateway** (`src/client/common.rs::mocks::MockGateway`)
   - Simulates IB Gateway/TWS server behavior
   - Binds to a random TCP port for real network testing
   - Handles the complete handshake protocol including magic token exchange
   - Records all incoming requests for verification
   - Sends pre-configured responses based on defined interactions

2. **ConnectionHandler** (internal to MockGateway)
   - Manages the TCP connection lifecycle
   - Performs protocol handshake (version exchange, client ID validation)
   - Routes requests to appropriate response handlers
   - Maintains request/response interaction mappings

3. **Setup Functions** (`src/client/common.rs::tests`)
   - Provide pre-configured MockGateway instances for specific test scenarios
   - Define expected request/response interactions
   - Examples: `setup_connect()`, `setup_server_time()`, `setup_contract_details()`

### Test Pattern Structure

#### 1. Create Setup Function
```rust
pub fn setup_contract_details() -> MockGateway {
    let mut gateway = MockGateway::new(server_versions::IPO_PRICES);
    
    gateway.add_interaction(
        OutgoingMessages::RequestContractData,
        vec![
            // Response messages in TWS protocol format
            "10\09000\0AAPL\0STK\0...", // ContractData message
            "52\01\09000\0",             // ContractDataEnd message
        ],
    );
    
    gateway.start().expect("Failed to start mock gateway");
    gateway
}
```

#### 2. Write Test (Sync)
```rust
#[test]
fn test_contract_details() {
    let gateway = setup_contract_details();
    let client = Client::connect(&gateway.address(), CLIENT_ID).expect("Failed to connect");
    
    // Execute the method under test
    let details = client.contract_details(&contract).expect("Failed to get details");
    
    // Verify response parsing
    assert_eq!(details[0].contract.symbol, "AAPL");
    
    // Verify request format
    let requests = gateway.requests();
    assert_eq!(requests[0], "9\08\09000\0...");
}
```

#### 3. Write Test (Async)
```rust
#[tokio::test]
async fn test_contract_details() {
    let gateway = setup_contract_details();
    let client = Client::connect(&gateway.address(), CLIENT_ID).await.expect("Failed to connect");
    
    // Execute the method under test
    let details = client.contract_details(&contract).await.expect("Failed to get details");
    
    // Verify response parsing (identical assertions as sync)
    assert_eq!(details[0].contract.symbol, "AAPL");
    
    // Verify request format
    let requests = gateway.requests();
    assert_eq!(requests[0], "9\08\09000\0...");
}
```

### Message Format

Messages follow the IB TWS protocol format using null-terminated strings:
- Format: `field1\0field2\0field3\0...`
- First field is typically the message type ID
- Subsequent fields depend on the specific message type
- Example: `"10\09000\0AAPL\0STK\0"` represents ContractData with request_id=9000, symbol=AAPL, security_type=STK

### Benefits of This Pattern

1. **Real Network Testing**: Uses actual TCP connections, testing the full network stack
2. **Protocol Verification**: Tests the complete handshake and message exchange
3. **Request Recording**: All requests are captured for detailed verification
4. **Deterministic Responses**: Pre-configured responses ensure consistent test results
5. **Shared Test Logic**: Common setup functions ensure sync/async tests are identical
6. **No External Dependencies**: Tests run without requiring IB Gateway/TWS installation

### Best Practices

1. **Reuse Setup Functions**: Create shared setup functions for common scenarios
2. **Test Both Directions**: Verify both request format (what client sends) and response parsing (what client receives)
3. **Use Meaningful Request IDs**: Use consistent IDs like 9000 for easier debugging
4. **Document Message Formats**: Add comments explaining the structure of request/response messages
5. **Keep Tests Identical**: Sync and async tests should have identical assertions
6. **Record Real Messages**: When implementing new tests, you can run against a real IB Gateway/TWS server with `IBAPI_RECORDING_DIR=/tmp/tws-messages` to capture actual protocol messages for use in MockGateway setup functions

## Unit Testing

The crate uses standard Rust unit testing patterns with `#[test]` for sync code and `#[tokio::test]` for async code.

### Running Tests

```bash
# Run all sync tests
cargo test --features sync

# Run all async tests  
cargo test --features async

# Run specific test module
cargo test --features sync client::sync::tests

# Run with logging
RUST_LOG=debug cargo test --features sync
```

### Test Organization

- Unit tests are placed in `#[cfg(test)]` modules within the same file as the code being tested
- Integration tests using MockGateway are in `src/client/sync.rs` and `src/client/async.rs`
- Common test utilities are in `src/client/common.rs`

## Coverage

The crate achieves 100% test coverage for all public Client methods using the MockGateway pattern. Every method has both sync and async tests to ensure feature parity.