Skip to main content
Glama
test_far_pointer_parsing.py12.5 kB
""" Test suite for far pointer syntax parsing in struct field definitions. Tests the parsing and handling of far pointer syntax (e.g., "type *32") where the number specifies the pointer size in bits. """ import pytest from unittest.mock import Mock, patch, MagicMock import json class TestFarPointerParsing: """Test suite for far pointer syntax parsing.""" def test_far_pointer_32bit_parsing(self): """Test parsing of 32-bit far pointer (type *32).""" # Test data: struct field with 32-bit far pointer field_type = "EffectData *32" # Expected result: 4-byte pointer (32 bits / 8 = 4 bytes) expected_pointer_size = 4 # Parse the type string parts = field_type.split("*") assert len(parts) == 2, "Should split into base type and size" base_type = parts[0].strip() size_str = parts[1].strip() assert base_type == "EffectData", "Base type should be EffectData" assert size_str == "32", "Size should be 32" # Verify size conversion pointer_size_bits = int(size_str) pointer_size_bytes = pointer_size_bits // 8 assert pointer_size_bytes == expected_pointer_size, "Should be 4 bytes" def test_far_pointer_16bit_parsing(self): """Test parsing of 16-bit far pointer (type *16).""" field_type = "void *16" parts = field_type.split("*") assert len(parts) == 2 base_type = parts[0].strip() size_str = parts[1].strip() assert base_type == "void" assert size_str == "16" pointer_size_bytes = int(size_str) // 8 assert pointer_size_bytes == 2, "16-bit pointer should be 2 bytes" def test_far_pointer_64bit_parsing(self): """Test parsing of 64-bit far pointer (type *64).""" field_type = "MyStruct *64" parts = field_type.split("*") assert len(parts) == 2 base_type = parts[0].strip() size_str = parts[1].strip() assert base_type == "MyStruct" assert size_str == "64" pointer_size_bytes = int(size_str) // 8 assert pointer_size_bytes == 8, "64-bit pointer should be 8 bytes" def test_regular_pointer_parsing(self): """Test that regular pointer syntax (type *) still works.""" field_type = "int *" parts = field_type.split("*") assert len(parts) == 2 base_type = parts[0].strip() size_str = parts[1].strip() assert base_type == "int" assert size_str == "", "Regular pointer should have empty size string" def test_pointer_with_spaces(self): """Test parsing pointer with spaces (type * 32).""" field_type = "char * 32" parts = field_type.split("*") assert len(parts) == 2 base_type = parts[0].strip() size_str = parts[1].strip() assert base_type == "char" assert size_str == "32" def test_invalid_pointer_size_zero(self): """Test handling of invalid pointer size (zero bits).""" field_type = "int *0" parts = field_type.split("*") size_str = parts[1].strip() pointer_size_bytes = int(size_str) // 8 assert pointer_size_bytes == 0, "Should detect zero size" def test_invalid_pointer_size_non_numeric(self): """Test handling of non-numeric pointer size.""" field_type = "int *abc" parts = field_type.split("*") size_str = parts[1].strip() with pytest.raises(ValueError): int(size_str) def test_multiple_asterisks(self): """Test handling of multiple asterisks in type name.""" # This is an edge case - pointer to pointer shouldn't match far pointer syntax field_type = "int **" parts = field_type.split("*") # Should have 3 parts: ["int ", "", ""] assert len(parts) >= 2 def test_no_space_between_type_and_asterisk(self): """Test parsing with no space before asterisk.""" field_type = "uint32_t*32" parts = field_type.split("*") assert len(parts) == 2 base_type = parts[0].strip() size_str = parts[1].strip() assert base_type == "uint32_t" assert size_str == "32" class TestFarPointerInBulkOperations: """Test far pointer syntax in bulk operations.""" def test_bulk_operation_with_far_pointer_field(self): """Test creating struct with far pointer field via bulk operations.""" bulk_operation = { "operations": [ { "endpoint": "/struct/create", "params": { "name": "WorldSpellEffect", "size": 0, "category_path": "" } }, { "endpoint": "/struct/insert_field", "params": { "struct_name": "WorldSpellEffect", "field_name": "activeFlag", "field_type": "uint8_t", "offset": 0, "length": -1, "comment": "0=inactive, 1=active" } }, { "endpoint": "/struct/insert_field", "params": { "struct_name": "WorldSpellEffect", "field_name": "spellType", "field_type": "uint8_t", "offset": 1, "length": -1, "comment": "Type of spell" } }, { "endpoint": "/struct/insert_field", "params": { "struct_name": "WorldSpellEffect", "field_name": "pEffectData", "field_type": "EffectData *32", "offset": 2, "length": -1, "comment": "Far pointer (32-bit) to effect data" } } ] } # Verify the bulk operation structure assert len(bulk_operation["operations"]) == 4 # Find the far pointer field operation far_pointer_op = bulk_operation["operations"][3] assert far_pointer_op["params"]["field_type"] == "EffectData *32" assert "*32" in far_pointer_op["params"]["field_type"] def test_multiple_far_pointers_different_sizes(self): """Test struct with multiple far pointers of different sizes.""" operations = [ { "endpoint": "/struct/insert_field", "params": { "struct_name": "TestStruct", "field_name": "ptr16", "field_type": "void *16", "offset": 0, "length": -1 } }, { "endpoint": "/struct/insert_field", "params": { "struct_name": "TestStruct", "field_name": "ptr32", "field_type": "int *32", "offset": 2, "length": -1 } }, { "endpoint": "/struct/insert_field", "params": { "struct_name": "TestStruct", "field_name": "ptr64", "field_type": "char *64", "offset": 6, "length": -1 } } ] # Verify all pointer types are present pointer_types = [op["params"]["field_type"] for op in operations] assert "void *16" in pointer_types assert "int *32" in pointer_types assert "char *64" in pointer_types class TestFarPointerEdgeCases: """Test edge cases for far pointer parsing.""" def test_pointer_size_odd_bits(self): """Test pointer with non-byte-aligned size.""" # 17 bits is not byte-aligned field_type = "int *17" parts = field_type.split("*") size_str = parts[1].strip() pointer_size_bits = int(size_str) # Integer division should give 2 bytes (17 // 8 = 2) pointer_size_bytes = pointer_size_bits // 8 assert pointer_size_bytes == 2 def test_very_large_pointer_size(self): """Test pointer with very large size.""" field_type = "void *128" parts = field_type.split("*") size_str = parts[1].strip() pointer_size_bytes = int(size_str) // 8 assert pointer_size_bytes == 16, "128-bit pointer should be 16 bytes" def test_pointer_with_complex_base_type(self): """Test far pointer with complex base type name.""" field_type = "struct MyComplexStruct *32" parts = field_type.split("*") base_type = parts[0].strip() size_str = parts[1].strip() assert base_type == "struct MyComplexStruct" assert size_str == "32" def test_pointer_with_underscore_in_base_type(self): """Test far pointer with underscore in base type.""" field_type = "my_custom_type_t *32" parts = field_type.split("*") base_type = parts[0].strip() assert base_type == "my_custom_type_t" assert parts[1].strip() == "32" def test_numeric_pattern_detection(self): """Test that numeric pattern is correctly detected.""" # Test valid numeric patterns valid_sizes = ["8", "16", "32", "64", "128"] for size in valid_sizes: assert size.isdigit(), f"{size} should be detected as numeric" # Test invalid patterns invalid_sizes = ["32x", "abc", "3.14", ""] for size in invalid_sizes[:-1]: # Skip empty string assert not size.replace(".", "").replace("-", "").isdigit() or "." in size or "-" in size class TestFarPointerBackwardCompatibility: """Test that far pointer changes don't break existing functionality.""" def test_regular_pointer_still_works(self): """Test that regular pointers without size still work.""" regular_pointers = [ "int *", "void *", "char *", "MyStruct *", "unsigned long *" ] for ptr in regular_pointers: parts = ptr.split("*") assert len(parts) == 2 base_type = parts[0].strip() size_str = parts[1].strip() # Regular pointers should have empty size string assert size_str == "", f"Regular pointer {ptr} should have no size" assert base_type != "", f"Regular pointer {ptr} should have base type" def test_no_asterisk_types_unaffected(self): """Test that types without asterisks are unaffected.""" simple_types = [ "int", "uint8_t", "char", "float", "double", "MyStruct" ] for type_name in simple_types: # These types shouldn't contain asterisks assert "*" not in type_name # And shouldn't be split parts = type_name.split("*") assert len(parts) == 1, f"{type_name} should not be split" class TestFarPointerSizeCalculations: """Test size calculations for far pointers.""" @pytest.mark.parametrize("bits,expected_bytes", [ (8, 1), (16, 2), (32, 4), (64, 8), (128, 16), (256, 32), ]) def test_pointer_size_conversion(self, bits, expected_bytes): """Test conversion from bits to bytes for various pointer sizes.""" calculated_bytes = bits // 8 assert calculated_bytes == expected_bytes, \ f"{bits} bits should be {expected_bytes} bytes" def test_pointer_size_alignment(self): """Test that pointer sizes are properly aligned.""" # Common pointer sizes should be powers of 2 common_sizes_bits = [8, 16, 32, 64, 128] for size_bits in common_sizes_bits: size_bytes = size_bits // 8 # Check if size is a power of 2 (for common architectures) # For bytes: 1, 2, 4, 8, 16 are all powers of 2 assert size_bytes > 0 # Verify the math assert size_bytes * 8 == size_bits

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/HK47196/GhidraMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server