qssh 0.0.2-alpha

Experimental quantum-safe SSH using post-quantum crypto. Research project - NOT for production. See LIMITATIONS.md
Documentation
use qssh::p2p::{P2pSession, PeerInfo};
use std::net::{IpAddr, Ipv4Addr};
use tokio;

#[tokio::test]
async fn test_p2p_session_creation() {
    let session = P2pSession::new().await;
    assert!(session.is_ok(), "Failed to create P2P session");
    
    let session = session.unwrap();
    let our_info = session.our_info();
    
    assert!(!our_info.peer_id.is_empty());
    assert!(!our_info.public_key.is_empty());
    assert!(our_info.addresses.is_empty()); // No addresses until we start listening
}

#[tokio::test]
async fn test_peer_info_serialization() {
    let peer_info = PeerInfo {
        peer_id: "test-peer-123".to_string(),
        public_key: vec![1, 2, 3, 4, 5],
        addresses: vec![
            format!("{}:{}", IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080),
            format!("{}:{}", IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 42),
        ],
        protocols: vec!["qssh/1.0".to_string()],
        last_seen: None,
    };
    
    let serialized = bincode::serialize(&peer_info).expect("Failed to serialize");
    let deserialized: PeerInfo = bincode::deserialize(&serialized).expect("Failed to deserialize");
    
    assert_eq!(peer_info.peer_id, deserialized.peer_id);
    assert_eq!(peer_info.public_key, deserialized.public_key);
    assert_eq!(peer_info.addresses, deserialized.addresses);
    assert_eq!(peer_info.protocols, deserialized.protocols);
}

#[tokio::test]
async fn test_p2p_discovery_methods() {
    use qssh::p2p::discovery::{DiscoveryMethod, DiscoveryService};
    
    let service = DiscoveryService::new(vec![
        DiscoveryMethod::LocalBroadcast,
        DiscoveryMethod::KnownPeers(vec![]),
    ]);
    
    // Should not panic
    let _ = service.discover_peers().await;
}

#[test]
fn test_nat_traversal_stun_packet() {
    use qssh::p2p::nat::StunMessage;
    
    let stun_msg = StunMessage {
        transaction_id: [1; 12],
        message_type: 0x0001, // Binding Request
        attributes: vec![],
    };
    
    let serialized = bincode::serialize(&stun_msg).expect("Failed to serialize STUN");
    let deserialized: StunMessage = bincode::deserialize(&serialized).expect("Failed to deserialize STUN");
    
    assert_eq!(stun_msg.transaction_id, deserialized.transaction_id);
    assert_eq!(stun_msg.message_type, deserialized.message_type);
}

#[tokio::test] 
async fn test_p2p_connection_state() {
    use qssh::p2p::ConnectionState;
    
    let state = ConnectionState::Connecting;
    assert!(matches!(state, ConnectionState::Connecting));
    
    let state = ConnectionState::Connected;
    assert!(matches!(state, ConnectionState::Connected));
    
    let state = ConnectionState::Disconnected;
    assert!(matches!(state, ConnectionState::Disconnected));
}

#[cfg(test)]
mod p2p_protocol_tests {
    use super::*;
    use qssh::p2p::{P2pMessage, P2pMessageType};
    
    #[test]
    fn test_p2p_message_types() {
        let msg = P2pMessage {
            msg_type: P2pMessageType::Hello,
            payload: vec![1, 2, 3],
        };
        
        let serialized = bincode::serialize(&msg).expect("Failed to serialize");
        let deserialized: P2pMessage = bincode::deserialize(&serialized).expect("Failed to deserialize");
        
        assert!(matches!(deserialized.msg_type, P2pMessageType::Hello));
        assert_eq!(msg.payload, deserialized.payload);
    }
    
    #[test]
    fn test_all_message_types() {
        let types = vec![
            P2pMessageType::Hello,
            P2pMessageType::HelloAck,
            P2pMessageType::KeyExchange,
            P2pMessageType::KeyExchangeAck,
            P2pMessageType::Data,
            P2pMessageType::Close,
        ];
        
        for msg_type in types {
            let msg = P2pMessage {
                msg_type,
                payload: vec![42; 10],
            };
            
            let serialized = bincode::serialize(&msg).expect("Failed to serialize");
            assert!(!serialized.is_empty());
        }
    }
}