justcode-core 0.3.0

Compact binary encoder/decoder with space-efficient encoding
Documentation
//! Integration tests for justcode-core

use justcode_core::{config, Decode, Encode};

#[derive(Encode, Decode, PartialEq, Debug, Clone)]
struct Point {
    x: f32,
    y: f32,
}

#[derive(Encode, Decode, PartialEq, Debug, Clone)]
struct Entity {
    id: u32,
    position: Point,
    health: f32,
    active: bool,
}

#[derive(Encode, Decode, PartialEq, Debug, Clone)]
struct World {
    entities: Vec<Entity>,
    name: String,
}

#[test]
fn test_complex_struct_roundtrip() {
    let config = config::standard();
    
    let world = World {
        entities: vec![
            Entity {
                id: 1,
                position: Point { x: 0.0, y: 4.0 },
                health: 100.0,
                active: true,
            },
            Entity {
                id: 2,
                position: Point { x: 10.0, y: 20.5 },
                health: 75.5,
                active: false,
            },
        ],
        name: "Test World".to_string(),
    };

    let encoded = justcode_core::encode_to_vec(&world, config).unwrap();
    let (decoded, len): (World, usize) = justcode_core::decode_from_slice(&encoded, config).unwrap();

    assert_eq!(world, decoded);
    assert_eq!(len, encoded.len());
}

#[test]
fn test_nested_structures() {
    let config = config::standard();
    
    let entities = vec![
        Entity {
            id: 1,
            position: Point { x: 1.0, y: 2.0 },
            health: 100.0,
            active: true,
        },
        Entity {
            id: 2,
            position: Point { x: 3.0, y: 4.0 },
            health: 50.0,
            active: false,
        },
    ];

    let encoded = justcode_core::encode_to_vec(&entities, config).unwrap();
    let (decoded, _): (Vec<Entity>, usize) = justcode_core::decode_from_slice(&encoded, config).unwrap();

    assert_eq!(entities, decoded);
}

#[test]
fn test_empty_collections() {
    let config = config::standard();
    
    let empty_world = World {
        entities: vec![],
        name: "Empty".to_string(),
    };

    let encoded = justcode_core::encode_to_vec(&empty_world, config).unwrap();
    let (decoded, _): (World, usize) = justcode_core::decode_from_slice(&encoded, config).unwrap();

    assert_eq!(empty_world, decoded);
}

#[test]
fn test_large_dataset() {
    let config = config::standard();
    
    let mut entities = Vec::new();
    for i in 0..1000 {
        entities.push(Entity {
            id: i,
            position: Point {
                x: i as f32,
                y: (i * 2) as f32,
            },
            health: 100.0,
            active: i % 2 == 0,
        });
    }

    let encoded = justcode_core::encode_to_vec(&entities, config).unwrap();
    let (decoded, _): (Vec<Entity>, usize) = justcode_core::decode_from_slice(&encoded, config).unwrap();

    assert_eq!(entities.len(), decoded.len());
    assert_eq!(entities, decoded);
}

#[test]
fn test_option_fields() {
    #[derive(Encode, Decode, PartialEq, Debug)]
    struct OptionalEntity {
        id: u32,
        name: Option<String>,
        metadata: Option<Vec<u8>>,
    }

    let config = config::standard();
    
    let entity1 = OptionalEntity {
        id: 1,
        name: Some("Entity 1".to_string()),
        metadata: Some(vec![1, 2, 3]),
    };

    let entity2 = OptionalEntity {
        id: 2,
        name: None,
        metadata: None,
    };

    let entities = vec![entity1, entity2];

    let encoded = justcode_core::encode_to_vec(&entities, config).unwrap();
    let (decoded, _): (Vec<OptionalEntity>, usize) = justcode_core::decode_from_slice(&encoded, config).unwrap();

    assert_eq!(entities, decoded);
}

// Note: Enum tests are commented out due to derive macro issues with tuple variants
// The derive macro needs to be fixed to properly handle tuple enum variants
/*
#[test]
fn test_enum_types() {
    #[derive(Encode, Decode, PartialEq, Debug)]
    enum Message {
        Ping,
        Pong,
        Data(Vec<u8>),
        Error(String),
    }

    let config = config::standard();
    
    let messages = vec![
        Message::Ping,
        Message::Pong,
        Message::Data(vec![1, 2, 3, 4, 5]),
        Message::Error("Something went wrong".to_string()),
    ];

    let encoded = justcode_core::encode_to_vec(&messages, config).unwrap();
    let (decoded, _): (Vec<Message>, usize) = justcode_core::decode_from_slice(&encoded, config).unwrap();

    assert_eq!(messages, decoded);
}
*/

#[test]
fn test_config_with_limit() {
    let config = config::standard().with_limit(100);
    
    let small_data = vec![1u8, 2, 3, 4, 5];
    let encoded = justcode_core::encode_to_vec(&small_data, config).unwrap();
    let (decoded, _): (Vec<u8>, usize) = justcode_core::decode_from_slice(&encoded, config).unwrap();
    assert_eq!(small_data, decoded);

    // Try to decode data that would exceed limit
    let large_data = vec![0u8; 200];
    let encoded = justcode_core::encode_to_vec(&large_data, config).unwrap();
    let result: Result<(Vec<u8>, usize), _> = justcode_core::decode_from_slice(&encoded, config);
    assert!(result.is_err());
}

#[test]
fn test_config_without_varint() {
    let config = config::standard().with_variable_int_encoding(false);
    
    let value = vec![1u32, 2, 3];
    let encoded = justcode_core::encode_to_vec(&value, config).unwrap();
    let (decoded, _): (Vec<u32>, usize) = justcode_core::decode_from_slice(&encoded, config).unwrap();
    assert_eq!(value, decoded);
}

#[test]
fn test_streaming_api() {
    use justcode_core::{reader::Reader, writer::Writer};

    let config = config::standard();
    let mut writer = Writer::new(config);
    
    let entity = Entity {
        id: 42,
        position: Point { x: 1.0, y: 2.0 },
        health: 100.0,
        active: true,
    };
    
    entity.encode(&mut writer).unwrap();
    let bytes = writer.into_bytes();
    
    let mut reader = Reader::new(&bytes, config);
    let decoded = Entity::decode(&mut reader).unwrap();
    
    assert_eq!(entity, decoded);
    assert_eq!(reader.bytes_read(), bytes.len());
}

#[test]
fn test_multiple_values_streaming() {
    use justcode_core::{reader::Reader, writer::Writer};

    let config = config::standard();
    let mut writer = Writer::new(config);
    
    let values = vec![
        Entity {
            id: 1,
            position: Point { x: 1.0, y: 2.0 },
            health: 100.0,
            active: true,
        },
        Entity {
            id: 2,
            position: Point { x: 3.0, y: 4.0 },
            health: 50.0,
            active: false,
        },
    ];
    
    values.encode(&mut writer).unwrap();
    let bytes = writer.into_bytes();
    
    let mut reader = Reader::new(&bytes, config);
    let decoded = Vec::<Entity>::decode(&mut reader).unwrap();
    
    assert_eq!(values, decoded);
}

#[test]
fn test_error_handling() {
    let config = config::standard();
    
    // Test decoding from incomplete data
    let incomplete_data = vec![0u8, 1, 2];
    let result: Result<(u32, usize), _> = justcode_core::decode_from_slice(&incomplete_data, config);
    assert!(result.is_err());
    
    // Test decoding with size limit
    let config = config::standard().with_limit(10);
    let large_data = vec![0u8; 100];
    let encoded = justcode_core::encode_to_vec(&large_data, config).unwrap();
    let result: Result<(Vec<u8>, usize), _> = justcode_core::decode_from_slice(&encoded, config);
    assert!(result.is_err());
}

#[test]
fn test_roundtrip_consistency() {
    let config = config::standard();
    
    let original = World {
        entities: vec![
            Entity {
                id: 1,
                position: Point { x: 10.5, y: 20.75 },
                health: 100.0,
                active: true,
            },
        ],
        name: "Test".to_string(),
    };
    
    // Encode and decode multiple times
    let mut current = original.clone();
    for _ in 0..5 {
        let encoded = justcode_core::encode_to_vec(&current, config).unwrap();
        let (decoded, _): (World, usize) = justcode_core::decode_from_slice(&encoded, config).unwrap();
        current = decoded;
    }
    
    assert_eq!(original, current);
}