extends SceneTree ## Test suite for Tile component ## ## Tests tile initialization, texture management, and gem types. const TestHelperClass = preload("res://tests/helpers/TestHelper.gd") var tile_scene: PackedScene var tile_instance: Node2D var test_viewport: SubViewport func _initialize(): # Wait for autoloads to initialize await process_frame await process_frame run_tests() # Exit after tests complete quit() func run_tests(): TestHelperClass.print_test_header("Tile Component") # Setup test environment setup_test_environment() # Run test suites test_basic_functionality() test_tile_constants() test_texture_management() test_gem_type_management() test_visual_feedback_system() test_state_management() test_input_validation() test_scaling_and_sizing() test_memory_safety() test_error_handling() # Cleanup cleanup_tests() TestHelperClass.print_test_footer("Tile Component") func setup_test_environment(): TestHelperClass.print_step("Test Environment Setup") # Load Tile scene tile_scene = load("res://scenes/game/gameplays/Tile.tscn") TestHelperClass.assert_not_null(tile_scene, "Tile scene loads successfully") # Create test viewport for isolated testing test_viewport = SubViewport.new() test_viewport.size = Vector2i(400, 400) root.add_child(test_viewport) # Instance Tile in test viewport if tile_scene: tile_instance = tile_scene.instantiate() test_viewport.add_child(tile_instance) TestHelperClass.assert_not_null( tile_instance, "Tile instance created successfully" ) # Wait for initialization await process_frame await process_frame func test_basic_functionality(): TestHelperClass.print_step("Basic Functionality") if not tile_instance: TestHelperClass.assert_true( false, "Tile instance not available for testing" ) return # Test that Tile has expected properties var expected_properties = [ "tile_type", "grid_position", "is_selected", "is_highlighted", "original_scale", "active_gem_types" ] for prop in expected_properties: TestHelperClass.assert_true( prop in tile_instance, "Tile has property: " + prop ) # Test that Tile has expected methods var expected_methods = [ "set_active_gem_types", "get_active_gem_count", "add_gem_type", "remove_gem_type", "force_reset_visual_state" ] TestHelperClass.assert_has_methods( tile_instance, expected_methods, "Tile component methods" ) # Test signals TestHelperClass.assert_true( tile_instance.has_signal("tile_selected"), "Tile has tile_selected signal" ) # Test sprite reference TestHelperClass.assert_not_null( tile_instance.sprite, "Sprite node is available" ) TestHelperClass.assert_true( tile_instance.sprite is Sprite2D, "Sprite is Sprite2D type" ) # Test group membership TestHelperClass.assert_true( tile_instance.is_in_group("tiles"), "Tile is in 'tiles' group" ) func test_tile_constants(): TestHelperClass.print_step("Tile Constants") if not tile_instance: return # Test TILE_SIZE constant TestHelperClass.assert_equal( 48, tile_instance.TILE_SIZE, "TILE_SIZE constant is correct" ) # Test all_gem_textures array TestHelperClass.assert_not_null( tile_instance.all_gem_textures, "All gem textures array exists" ) TestHelperClass.assert_true( tile_instance.all_gem_textures is Array, "All gem textures is Array type" ) TestHelperClass.assert_equal( 8, tile_instance.all_gem_textures.size(), "All gem textures has expected count" ) # Test that all gem textures are valid for i in range(tile_instance.all_gem_textures.size()): var texture = tile_instance.all_gem_textures[i] TestHelperClass.assert_not_null( texture, "Gem texture %d is not null" % i ) TestHelperClass.assert_true( texture is Texture2D, "Gem texture %d is Texture2D type" % i ) func test_texture_management(): TestHelperClass.print_step("Texture Management") if not tile_instance: return # Test default gem types initialization TestHelperClass.assert_not_null( tile_instance.active_gem_types, "Active gem types is initialized" ) TestHelperClass.assert_true( tile_instance.active_gem_types is Array, "Active gem types is Array type" ) TestHelperClass.assert_true( tile_instance.active_gem_types.size() > 0, "Active gem types has content" ) # Test texture assignment for valid tile types var original_type = tile_instance.tile_type for i in range(min(3, tile_instance.active_gem_types.size())): tile_instance.tile_type = i TestHelperClass.assert_equal( i, tile_instance.tile_type, "Tile type set correctly to %d" % i ) if tile_instance.sprite: TestHelperClass.assert_not_null( tile_instance.sprite.texture, "Sprite texture assigned for type %d" % i ) # Restore original type tile_instance.tile_type = original_type func test_gem_type_management(): TestHelperClass.print_step("Gem Type Management") if not tile_instance: return # Store original state var original_gem_types = tile_instance.active_gem_types.duplicate() # Test set_active_gem_types with valid array var test_gems = [0, 1, 2] tile_instance.set_active_gem_types(test_gems) TestHelperClass.assert_equal( 3, tile_instance.get_active_gem_count(), "Active gem count set correctly" ) # Test add_gem_type var add_result = tile_instance.add_gem_type(3) TestHelperClass.assert_true(add_result, "Valid gem type added successfully") TestHelperClass.assert_equal( 4, tile_instance.get_active_gem_count(), "Gem count increased after addition" ) # Test adding duplicate gem type var duplicate_result = tile_instance.add_gem_type(3) TestHelperClass.assert_false( duplicate_result, "Duplicate gem type addition rejected" ) TestHelperClass.assert_equal( 4, tile_instance.get_active_gem_count(), "Gem count unchanged after duplicate" ) # Test add_gem_type with invalid index var invalid_add = tile_instance.add_gem_type(99) TestHelperClass.assert_false( invalid_add, "Invalid gem index addition rejected" ) # Test remove_gem_type var remove_result = tile_instance.remove_gem_type(3) TestHelperClass.assert_true( remove_result, "Valid gem type removed successfully" ) TestHelperClass.assert_equal( 3, tile_instance.get_active_gem_count(), "Gem count decreased after removal" ) # Test removing non-existent gem type var nonexistent_remove = tile_instance.remove_gem_type(99) TestHelperClass.assert_false( nonexistent_remove, "Non-existent gem type removal rejected" ) # Test minimum gem types protection tile_instance.set_active_gem_types([0, 1]) # Set to minimum var protected_remove = tile_instance.remove_gem_type(0) TestHelperClass.assert_false( protected_remove, "Minimum gem types protection active" ) TestHelperClass.assert_equal( 2, tile_instance.get_active_gem_count(), "Minimum gem count preserved" ) # Restore original state tile_instance.set_active_gem_types(original_gem_types) func test_visual_feedback_system(): TestHelperClass.print_step("Visual Feedback System") if not tile_instance: return # Store original state var original_selected = tile_instance.is_selected var original_highlighted = tile_instance.is_highlighted # Test selection visual feedback tile_instance.is_selected = true TestHelperClass.assert_true( tile_instance.is_selected, "Selection state set correctly" ) # Wait for potential animation await process_frame if tile_instance.sprite: # Test that modulate is brighter when selected var modulate = tile_instance.sprite.modulate TestHelperClass.assert_true( modulate.r > 1.0 or modulate.g > 1.0 or modulate.b > 1.0, "Selected tile has brighter modulate" ) # Test highlight visual feedback tile_instance.is_selected = false tile_instance.is_highlighted = true TestHelperClass.assert_true( tile_instance.is_highlighted, "Highlight state set correctly" ) # Wait for potential animation await process_frame # Test normal state tile_instance.is_highlighted = false TestHelperClass.assert_false( tile_instance.is_highlighted, "Normal state restored" ) # Test force reset tile_instance.is_selected = true tile_instance.is_highlighted = true tile_instance.force_reset_visual_state() TestHelperClass.assert_false( tile_instance.is_selected, "Force reset clears selection" ) TestHelperClass.assert_false( tile_instance.is_highlighted, "Force reset clears highlight" ) # Restore original state tile_instance.is_selected = original_selected tile_instance.is_highlighted = original_highlighted func test_state_management(): TestHelperClass.print_step("State Management") if not tile_instance: return # Test initial state TestHelperClass.assert_true( tile_instance.tile_type >= 0, "Initial tile type is non-negative" ) TestHelperClass.assert_true( tile_instance.grid_position is Vector2i, "Grid position is Vector2i type" ) TestHelperClass.assert_true( tile_instance.original_scale is Vector2, "Original scale is Vector2 type" ) # Test tile type bounds checking var original_type = tile_instance.tile_type var max_valid_type = tile_instance.active_gem_types.size() - 1 # Test valid tile type if max_valid_type >= 0: tile_instance.tile_type = max_valid_type TestHelperClass.assert_equal( max_valid_type, tile_instance.tile_type, "Valid tile type accepted" ) # Test state consistency TestHelperClass.assert_true( tile_instance.tile_type < tile_instance.active_gem_types.size(), "Tile type within active gems range" ) # Restore original type tile_instance.tile_type = original_type func test_input_validation(): TestHelperClass.print_step("Input Validation") if not tile_instance: return # Test empty gem types array var original_gems = tile_instance.active_gem_types.duplicate() tile_instance.set_active_gem_types([]) # Should fall back to defaults or maintain previous state TestHelperClass.assert_true( tile_instance.get_active_gem_count() > 0, "Empty gem array handled gracefully" ) # Test null gem types array tile_instance.set_active_gem_types(null) TestHelperClass.assert_true( tile_instance.get_active_gem_count() > 0, "Null gem array handled gracefully" ) # Test invalid gem indices in array tile_instance.set_active_gem_types([0, 1, 99, 2]) # 99 is invalid # Should use fallback or filter invalid indices TestHelperClass.assert_true( tile_instance.get_active_gem_count() > 0, "Invalid gem indices handled gracefully" ) # Test negative gem indices var negative_add = tile_instance.add_gem_type(-1) TestHelperClass.assert_false(negative_add, "Negative gem index rejected") # Test out-of-bounds gem indices var oob_add = tile_instance.add_gem_type( tile_instance.all_gem_textures.size() ) TestHelperClass.assert_false(oob_add, "Out-of-bounds gem index rejected") # Restore original state tile_instance.set_active_gem_types(original_gems) func test_scaling_and_sizing(): TestHelperClass.print_step("Scaling and Sizing") if not tile_instance: return # Test original scale calculation TestHelperClass.assert_not_null( tile_instance.original_scale, "Original scale is calculated" ) TestHelperClass.assert_true( tile_instance.original_scale.x > 0, "Original scale X is positive" ) TestHelperClass.assert_true( tile_instance.original_scale.y > 0, "Original scale Y is positive" ) # Test that tile size is respected if tile_instance.sprite and tile_instance.sprite.texture: var texture_size = tile_instance.sprite.texture.get_size() var scaled_size = texture_size * tile_instance.original_scale var max_dimension = max(scaled_size.x, scaled_size.y) TestHelperClass.assert_true( max_dimension <= tile_instance.TILE_SIZE + 1, "Scaled tile fits within TILE_SIZE" ) # Test scale animation for visual feedback var original_scale = ( tile_instance.sprite.scale if tile_instance.sprite else Vector2.ONE ) # Test selection scaling tile_instance.is_selected = true await process_frame await process_frame # Wait for animation if tile_instance.sprite: var selected_scale = tile_instance.sprite.scale TestHelperClass.assert_true( selected_scale.x >= original_scale.x, "Selected tile scale is larger or equal" ) # Reset to normal tile_instance.is_selected = false await process_frame await process_frame func test_memory_safety(): TestHelperClass.print_step("Memory Safety") if not tile_instance: return # Test sprite null checking var original_sprite = tile_instance.sprite tile_instance.sprite = null # These operations should not crash tile_instance.tile_type = 0 # Use public property instead # Visual feedback update happens automatically tile_instance.force_reset_visual_state() TestHelperClass.assert_true(true, "Null sprite operations handled safely") # Restore sprite tile_instance.sprite = original_sprite # Test valid instance checking in visual updates if tile_instance.sprite: TestHelperClass.assert_true( is_instance_valid(tile_instance.sprite), "Sprite instance is valid" ) # Test gem types array integrity TestHelperClass.assert_true( tile_instance.active_gem_types is Array, "Active gem types maintains Array type" ) # Test that gem indices are within bounds for gem_index in tile_instance.active_gem_types: TestHelperClass.assert_true(gem_index >= 0, "Gem index is non-negative") TestHelperClass.assert_true( gem_index < tile_instance.all_gem_textures.size(), "Gem index within texture array bounds" ) func test_error_handling(): TestHelperClass.print_step("Error Handling") if not tile_instance: return # Test graceful handling of missing sprite during initialization var backup_sprite = tile_instance.sprite tile_instance.sprite = null # Test that tile type setting handles null sprite gracefully tile_instance.tile_type = 0 # Use public property instead TestHelperClass.assert_true( true, "Tile type setting handles null sprite gracefully" ) # Test that scaling handles null sprite gracefully # Force redraw to trigger scaling logic tile_instance.queue_redraw() TestHelperClass.assert_true( true, "Sprite scaling handles null sprite gracefully" ) # Restore sprite tile_instance.sprite = backup_sprite # Test invalid tile type handling var original_type = tile_instance.tile_type tile_instance.tile_type = -1 # Invalid negative type tile_instance.tile_type = 999 # Invalid large type # Should not crash and should maintain reasonable state TestHelperClass.assert_true(true, "Invalid tile types handled gracefully") # Restore original type tile_instance.tile_type = original_type # Test array bounds protection var large_gem_types = [] for i in range(50): # Create array larger than texture array large_gem_types.append(i) tile_instance.set_active_gem_types(large_gem_types) # Should fall back to safe defaults TestHelperClass.assert_true( ( tile_instance.get_active_gem_count() <= tile_instance.all_gem_textures.size() ), "Large gem array handled safely" ) func cleanup_tests(): TestHelperClass.print_step("Cleanup") # Clean up tile instance if tile_instance and is_instance_valid(tile_instance): tile_instance.queue_free() # Clean up test viewport if test_viewport and is_instance_valid(test_viewport): test_viewport.queue_free() # Wait for cleanup await process_frame TestHelperClass.assert_true(true, "Test cleanup completed")