unity-asset-binary 0.2.0

Unity binary file format parser (AssetBundle, SerializedFile)
Documentation
//! UnityPy TypeTree Tests Port
//!
//! This file ports the TypeTree tests from UnityPy's test_typetree.py to Rust
//! to ensure our TypeTree implementation is compatible.

#![allow(unused_imports)]

use std::collections::HashMap;
use unity_asset_binary::typetree::{TypeTree, TypeTreeNode};

/// Test basic TypeTree node creation (port of test_typetreenode)
#[test]
fn test_typetree_node_creation() {
    println!("Testing TypeTree node creation...");

    // Create a basic node similar to UnityPy's test
    let mut node = TypeTreeNode::new();
    node.type_name = "TestNode".to_string();
    node.name = "TestNode".to_string();
    node.level = 0;
    node.byte_size = 0;

    assert_eq!(node.type_name, "TestNode");
    assert_eq!(node.name, "TestNode");
    assert_eq!(node.level, 0);
    assert_eq!(node.byte_size, 0);

    println!("  ✓ Basic node creation successful");
}

/// Generate a dummy node for testing (port of generate_dummy_node)
fn generate_dummy_node(type_name: &str, name: &str) -> TypeTreeNode {
    let mut node = TypeTreeNode::new();
    node.type_name = type_name.to_string();
    node.name = name.to_string();
    node.level = 0;
    node.byte_size = 0;
    node
}

/// Test data for simple node types (port of SIMPLE_NODE_SAMPLES)
const SIMPLE_NODE_SAMPLES: &[(&[&str], &str, (i64, i64))] = &[
    (&["SInt8"], "int", (-128, 128)),
    (&["SInt16", "short"], "int", (-32768, 32768)),
    (&["SInt32", "int"], "int", (-2147483648, 2147483648)),
    (&["UInt8", "char"], "int", (0, 256)),
    (&["UInt16", "unsigned short"], "int", (0, 65536)),
    (&["UInt32", "unsigned int", "Type*"], "int", (0, 4294967296)),
    (&["float"], "float", (-1, 1)),
    (&["double"], "float", (-1, 1)),
    (&["bool"], "bool", (0, 1)),
];

/// Test simple node types (port of test_simple_nodes)
#[test]
fn test_simple_nodes() {
    println!("Testing simple node types...");

    for (type_names, py_type, bounds) in SIMPLE_NODE_SAMPLES {
        println!("  Testing types: {:?} ({})", type_names, py_type);

        for type_name in *type_names {
            let node = generate_dummy_node(type_name, "");

            // Verify node properties
            assert_eq!(node.type_name, *type_name);
            assert_eq!(node.level, 0);

            // Test bounds checking (simplified version)
            match *py_type {
                "int" => {
                    assert!(bounds.0 < bounds.1, "Invalid bounds for {}", type_name);
                }
                "float" => {
                    assert!(bounds.0 <= bounds.1, "Invalid bounds for {}", type_name);
                }
                "bool" => {
                    assert_eq!(bounds, &(0, 1), "Bool should have bounds (0, 1)");
                }
                _ => {}
            }
        }
    }

    println!("  ✓ Simple node types test completed");
}

/// Test array node generation (port of test_simple_nodes_array)
#[test]
fn test_simple_nodes_array() {
    println!("Testing array node generation...");

    // Generate a list node structure (similar to UnityPy's generate_list_node)
    fn generate_list_node(item_node: TypeTreeNode) -> TypeTreeNode {
        let mut root = generate_dummy_node("root", "root");
        let mut array = generate_dummy_node("Array", "Array");

        // In UnityPy, array.m_Children = [None, item_node]
        // We'll simulate this with a simplified structure
        array.children = vec![item_node];
        root.children = vec![array];

        root
    }

    // Test with a few simple types
    let test_types = &["int", "float", "bool"];

    for type_name in test_types {
        let item_node = generate_dummy_node(type_name, "");
        let array_node = generate_list_node(item_node);

        // Verify structure
        assert_eq!(array_node.type_name, "root");
        assert_eq!(array_node.children.len(), 1);
        assert_eq!(array_node.children[0].type_name, "Array");
        assert_eq!(array_node.children[0].children.len(), 1);
        assert_eq!(array_node.children[0].children[0].type_name, *type_name);
    }

    println!("  ✓ Array node generation test completed");
}

/// Test TypeTree creation and basic operations
#[test]
fn test_typetree_creation() {
    println!("Testing TypeTree creation...");

    // Create a simple TypeTree
    let root_node = generate_dummy_node("GameObject", "");
    let mut type_tree = TypeTree::new();
    type_tree.nodes.push(root_node);

    // Verify basic properties
    assert_eq!(type_tree.nodes.len(), 1);
    assert_eq!(type_tree.nodes[0].type_name, "GameObject");

    println!("  ✓ TypeTree creation successful");
}

/// Test node traversal and hierarchy
#[test]
fn test_node_traversal() {
    println!("Testing node traversal...");

    // Create a more complex node hierarchy
    let mut root = generate_dummy_node("GameObject", "");
    let mut component = generate_dummy_node("Component", "m_Component");
    let transform = generate_dummy_node("Transform", "m_Transform");

    component.children = vec![transform];
    root.children = vec![component];

    // Test traversal
    assert_eq!(root.children.len(), 1);
    assert_eq!(root.children[0].type_name, "Component");
    assert_eq!(root.children[0].children.len(), 1);
    assert_eq!(root.children[0].children[0].type_name, "Transform");

    println!("  ✓ Node traversal test completed");
}

/// Test node equality and comparison
#[test]
fn test_node_equality() {
    println!("Testing node equality...");

    let node1 = generate_dummy_node("TestType", "testName");
    let node2 = generate_dummy_node("TestType", "testName");
    let node3 = generate_dummy_node("DifferentType", "testName");

    // Test basic equality (this would need to be implemented in TypeTreeNode)
    assert_eq!(node1.type_name, node2.type_name);
    assert_eq!(node1.name, node2.name);
    assert_ne!(node1.type_name, node3.type_name);

    println!("  ✓ Node equality test completed");
}

/// Memory usage test (simplified version of UnityPy's memory leak detection)
#[test]
fn test_memory_usage() {
    println!("Testing memory usage...");

    // Create and destroy many nodes to check for obvious memory issues
    let iterations = 1000;

    for i in 0..iterations {
        let node = generate_dummy_node(&format!("TestType{}", i), &format!("testName{}", i));

        // Create some children
        let mut children = Vec::new();
        for j in 0..10 {
            children.push(generate_dummy_node(
                &format!("ChildType{}", j),
                &format!("child{}", j),
            ));
        }

        // This tests that we can create and drop nodes without issues
        drop(node);
        drop(children);
    }

    println!(
        "  ✓ Memory usage test completed (created and dropped {} nodes)",
        iterations * 11
    );
}

/// Test TypeTree string resolution (port of test_string_resolution)
#[test]
fn test_string_resolution() {
    println!("Testing string resolution...");

    // Test that we can handle string types properly
    let string_node = generate_dummy_node("string", "m_Name");

    assert_eq!(string_node.type_name, "string");
    assert_eq!(string_node.name, "m_Name");

    // Test common Unity string fields
    let common_string_fields = &[
        ("string", "m_Name"),
        ("string", "m_Tag"),
        ("string", "m_Path"),
        ("string", "m_Script"),
    ];

    for (type_name, field_name) in common_string_fields {
        let node = generate_dummy_node(type_name, field_name);
        assert_eq!(node.type_name, *type_name);
        assert_eq!(node.name, *field_name);
    }

    println!("  ✓ String resolution test completed");
}

/// Test primitive type detection
#[test]
fn test_primitive_detection() {
    println!("Testing primitive type detection...");

    let primitive_types = &[
        "bool", "char", "SInt8", "UInt8", "SInt16", "UInt16", "SInt32", "UInt32", "SInt64",
        "UInt64", "float", "double",
    ];

    let non_primitive_types = &[
        "string",
        "Array",
        "GameObject",
        "Transform",
        "Component",
        "Vector3",
    ];

    for type_name in primitive_types {
        let node = generate_dummy_node(type_name, "");
        // We would implement is_primitive() method on TypeTreeNode
        // For now, just verify the node was created correctly
        assert_eq!(node.type_name, *type_name);
    }

    for type_name in non_primitive_types {
        let node = generate_dummy_node(type_name, "");
        assert_eq!(node.type_name, *type_name);
    }

    println!("  ✓ Primitive type detection test completed");
}

/// Test array type detection
#[test]
fn test_array_detection() {
    println!("Testing array type detection...");

    let array_node = generate_dummy_node("Array", "m_Array");
    assert_eq!(array_node.type_name, "Array");

    // Test vector types (which are array-like in Unity)
    let vector_types = &["vector", "Vector3", "Vector2", "Vector4", "Quaternion"];

    for type_name in vector_types {
        let node = generate_dummy_node(type_name, "");
        assert_eq!(node.type_name, *type_name);
    }

    println!("  ✓ Array type detection test completed");
}

/// Integration test combining multiple TypeTree features
#[test]
fn test_typetree_integration() {
    println!("Testing TypeTree integration...");

    // Create a complex GameObject-like structure
    let mut game_object = generate_dummy_node("GameObject", "");

    // Add components
    let mut transform = generate_dummy_node("Transform", "m_Transform");
    let position = generate_dummy_node("Vector3", "m_LocalPosition");
    let rotation = generate_dummy_node("Quaternion", "m_LocalRotation");
    let scale = generate_dummy_node("Vector3", "m_LocalScale");

    transform.children = vec![position, rotation, scale];

    let mut mesh_renderer = generate_dummy_node("MeshRenderer", "m_MeshRenderer");
    let materials = generate_dummy_node("Array", "m_Materials");
    mesh_renderer.children = vec![materials];

    game_object.children = vec![transform, mesh_renderer];

    // Create TypeTree
    let mut type_tree = TypeTree::new();
    type_tree.nodes.push(game_object);

    // Verify structure
    assert_eq!(type_tree.nodes.len(), 1);
    let root = &type_tree.nodes[0];
    assert_eq!(root.type_name, "GameObject");
    assert_eq!(root.children.len(), 2);

    // Verify Transform component
    let transform_comp = &root.children[0];
    assert_eq!(transform_comp.type_name, "Transform");
    assert_eq!(transform_comp.children.len(), 3);

    // Verify MeshRenderer component
    let mesh_renderer_comp = &root.children[1];
    assert_eq!(mesh_renderer_comp.type_name, "MeshRenderer");
    assert_eq!(mesh_renderer_comp.children.len(), 1);

    println!("  ✓ TypeTree integration test completed");
}