Add gdlint and gdformat scripts
This commit is contained in:
@@ -10,6 +10,7 @@ var match3_scene: PackedScene
|
||||
var match3_instance: Node2D
|
||||
var test_viewport: SubViewport
|
||||
|
||||
|
||||
func _initialize():
|
||||
# Wait for autoloads to initialize
|
||||
await process_frame
|
||||
@@ -20,6 +21,7 @@ func _initialize():
|
||||
# Exit after tests complete
|
||||
quit()
|
||||
|
||||
|
||||
func run_tests():
|
||||
TestHelper.print_test_header("Match3 Gameplay")
|
||||
|
||||
@@ -43,6 +45,7 @@ func run_tests():
|
||||
|
||||
TestHelper.print_test_footer("Match3 Gameplay")
|
||||
|
||||
|
||||
func setup_test_environment():
|
||||
TestHelper.print_step("Test Environment Setup")
|
||||
|
||||
@@ -65,6 +68,7 @@ func setup_test_environment():
|
||||
await process_frame
|
||||
await process_frame
|
||||
|
||||
|
||||
func test_basic_functionality():
|
||||
TestHelper.print_step("Basic Functionality")
|
||||
|
||||
@@ -73,17 +77,26 @@ func test_basic_functionality():
|
||||
return
|
||||
|
||||
# Test that Match3 has expected properties
|
||||
var expected_properties = ["GRID_SIZE", "TILE_TYPES", "grid", "current_state", "selected_tile", "cursor_position"]
|
||||
var expected_properties = [
|
||||
"GRID_SIZE", "TILE_TYPES", "grid", "current_state", "selected_tile", "cursor_position"
|
||||
]
|
||||
for prop in expected_properties:
|
||||
TestHelper.assert_true(prop in match3_instance, "Match3 has property: " + prop)
|
||||
|
||||
# Test that Match3 has expected methods
|
||||
var expected_methods = ["_has_match_at", "_check_for_matches", "_get_match_line", "_clear_matches"]
|
||||
var expected_methods = [
|
||||
"_has_match_at", "_check_for_matches", "_get_match_line", "_clear_matches"
|
||||
]
|
||||
TestHelper.assert_has_methods(match3_instance, expected_methods, "Match3 gameplay methods")
|
||||
|
||||
# Test signals
|
||||
TestHelper.assert_true(match3_instance.has_signal("score_changed"), "Match3 has score_changed signal")
|
||||
TestHelper.assert_true(match3_instance.has_signal("grid_state_loaded"), "Match3 has grid_state_loaded signal")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_signal("score_changed"), "Match3 has score_changed signal"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_signal("grid_state_loaded"), "Match3 has grid_state_loaded signal"
|
||||
)
|
||||
|
||||
|
||||
func test_constants_and_safety_limits():
|
||||
TestHelper.print_step("Constants and Safety Limits")
|
||||
@@ -94,26 +107,52 @@ func test_constants_and_safety_limits():
|
||||
# Test safety constants exist
|
||||
TestHelper.assert_true("MAX_GRID_SIZE" in match3_instance, "MAX_GRID_SIZE constant exists")
|
||||
TestHelper.assert_true("MAX_TILE_TYPES" in match3_instance, "MAX_TILE_TYPES constant exists")
|
||||
TestHelper.assert_true("MAX_CASCADE_ITERATIONS" in match3_instance, "MAX_CASCADE_ITERATIONS constant exists")
|
||||
TestHelper.assert_true(
|
||||
"MAX_CASCADE_ITERATIONS" in match3_instance, "MAX_CASCADE_ITERATIONS constant exists"
|
||||
)
|
||||
TestHelper.assert_true("MIN_GRID_SIZE" in match3_instance, "MIN_GRID_SIZE constant exists")
|
||||
TestHelper.assert_true("MIN_TILE_TYPES" in match3_instance, "MIN_TILE_TYPES constant exists")
|
||||
|
||||
# Test safety limit values are reasonable
|
||||
TestHelper.assert_equal(15, match3_instance.MAX_GRID_SIZE, "MAX_GRID_SIZE is reasonable")
|
||||
TestHelper.assert_equal(10, match3_instance.MAX_TILE_TYPES, "MAX_TILE_TYPES is reasonable")
|
||||
TestHelper.assert_equal(20, match3_instance.MAX_CASCADE_ITERATIONS, "MAX_CASCADE_ITERATIONS prevents infinite loops")
|
||||
TestHelper.assert_equal(
|
||||
20, match3_instance.MAX_CASCADE_ITERATIONS, "MAX_CASCADE_ITERATIONS prevents infinite loops"
|
||||
)
|
||||
TestHelper.assert_equal(3, match3_instance.MIN_GRID_SIZE, "MIN_GRID_SIZE is reasonable")
|
||||
TestHelper.assert_equal(3, match3_instance.MIN_TILE_TYPES, "MIN_TILE_TYPES is reasonable")
|
||||
|
||||
# Test current values are within safety limits
|
||||
TestHelper.assert_in_range(match3_instance.GRID_SIZE.x, match3_instance.MIN_GRID_SIZE, match3_instance.MAX_GRID_SIZE, "Grid width within safety limits")
|
||||
TestHelper.assert_in_range(match3_instance.GRID_SIZE.y, match3_instance.MIN_GRID_SIZE, match3_instance.MAX_GRID_SIZE, "Grid height within safety limits")
|
||||
TestHelper.assert_in_range(match3_instance.TILE_TYPES, match3_instance.MIN_TILE_TYPES, match3_instance.MAX_TILE_TYPES, "Tile types within safety limits")
|
||||
TestHelper.assert_in_range(
|
||||
match3_instance.GRID_SIZE.x,
|
||||
match3_instance.MIN_GRID_SIZE,
|
||||
match3_instance.MAX_GRID_SIZE,
|
||||
"Grid width within safety limits"
|
||||
)
|
||||
TestHelper.assert_in_range(
|
||||
match3_instance.GRID_SIZE.y,
|
||||
match3_instance.MIN_GRID_SIZE,
|
||||
match3_instance.MAX_GRID_SIZE,
|
||||
"Grid height within safety limits"
|
||||
)
|
||||
TestHelper.assert_in_range(
|
||||
match3_instance.TILE_TYPES,
|
||||
match3_instance.MIN_TILE_TYPES,
|
||||
match3_instance.MAX_TILE_TYPES,
|
||||
"Tile types within safety limits"
|
||||
)
|
||||
|
||||
# Test timing constants
|
||||
TestHelper.assert_true("CASCADE_WAIT_TIME" in match3_instance, "CASCADE_WAIT_TIME constant exists")
|
||||
TestHelper.assert_true("SWAP_ANIMATION_TIME" in match3_instance, "SWAP_ANIMATION_TIME constant exists")
|
||||
TestHelper.assert_true("TILE_DROP_WAIT_TIME" in match3_instance, "TILE_DROP_WAIT_TIME constant exists")
|
||||
TestHelper.assert_true(
|
||||
"CASCADE_WAIT_TIME" in match3_instance, "CASCADE_WAIT_TIME constant exists"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
"SWAP_ANIMATION_TIME" in match3_instance, "SWAP_ANIMATION_TIME constant exists"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
"TILE_DROP_WAIT_TIME" in match3_instance, "TILE_DROP_WAIT_TIME constant exists"
|
||||
)
|
||||
|
||||
|
||||
func test_grid_initialization():
|
||||
TestHelper.print_step("Grid Initialization")
|
||||
@@ -134,7 +173,9 @@ func test_grid_initialization():
|
||||
# Test each row has correct width
|
||||
for y in range(match3_instance.grid.size()):
|
||||
if y < expected_height:
|
||||
TestHelper.assert_equal(expected_width, match3_instance.grid[y].size(), "Grid row %d has correct width" % y)
|
||||
TestHelper.assert_equal(
|
||||
expected_width, match3_instance.grid[y].size(), "Grid row %d has correct width" % y
|
||||
)
|
||||
|
||||
# Test tiles are properly instantiated
|
||||
var tile_count = 0
|
||||
@@ -147,15 +188,25 @@ func test_grid_initialization():
|
||||
|
||||
if tile and is_instance_valid(tile):
|
||||
valid_tile_count += 1
|
||||
TestHelper.assert_true("tile_type" in tile, "Tile at (%d,%d) has tile_type property" % [x, y])
|
||||
TestHelper.assert_true("grid_position" in tile, "Tile at (%d,%d) has grid_position property" % [x, y])
|
||||
TestHelper.assert_true(
|
||||
"tile_type" in tile, "Tile at (%d,%d) has tile_type property" % [x, y]
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
"grid_position" in tile, "Tile at (%d,%d) has grid_position property" % [x, y]
|
||||
)
|
||||
|
||||
# Test tile type is within valid range
|
||||
if "tile_type" in tile:
|
||||
TestHelper.assert_in_range(tile.tile_type, 0, match3_instance.TILE_TYPES - 1, "Tile type in valid range")
|
||||
TestHelper.assert_in_range(
|
||||
tile.tile_type,
|
||||
0,
|
||||
match3_instance.TILE_TYPES - 1,
|
||||
"Tile type in valid range"
|
||||
)
|
||||
|
||||
TestHelper.assert_equal(tile_count, valid_tile_count, "All grid positions have valid tiles")
|
||||
|
||||
|
||||
func test_grid_layout_calculation():
|
||||
TestHelper.print_step("Grid Layout Calculation")
|
||||
|
||||
@@ -164,7 +215,9 @@ func test_grid_layout_calculation():
|
||||
|
||||
# Test tile size calculation
|
||||
TestHelper.assert_true(match3_instance.tile_size > 0, "Tile size is positive")
|
||||
TestHelper.assert_true(match3_instance.tile_size <= 200, "Tile size is reasonable (not too large)")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.tile_size <= 200, "Tile size is reasonable (not too large)"
|
||||
)
|
||||
|
||||
# Test grid offset
|
||||
TestHelper.assert_not_null(match3_instance.grid_offset, "Grid offset is set")
|
||||
@@ -173,10 +226,13 @@ func test_grid_layout_calculation():
|
||||
|
||||
# Test layout constants
|
||||
TestHelper.assert_equal(0.8, match3_instance.SCREEN_WIDTH_USAGE, "Screen width usage constant")
|
||||
TestHelper.assert_equal(0.7, match3_instance.SCREEN_HEIGHT_USAGE, "Screen height usage constant")
|
||||
TestHelper.assert_equal(
|
||||
0.7, match3_instance.SCREEN_HEIGHT_USAGE, "Screen height usage constant"
|
||||
)
|
||||
TestHelper.assert_equal(50.0, match3_instance.GRID_LEFT_MARGIN, "Grid left margin constant")
|
||||
TestHelper.assert_equal(50.0, match3_instance.GRID_TOP_MARGIN, "Grid top margin constant")
|
||||
|
||||
|
||||
func test_state_management():
|
||||
TestHelper.print_step("State Management")
|
||||
|
||||
@@ -196,7 +252,10 @@ func test_state_management():
|
||||
|
||||
# Test instance ID for debugging
|
||||
TestHelper.assert_true("instance_id" in match3_instance, "Instance ID exists for debugging")
|
||||
TestHelper.assert_true(match3_instance.instance_id.begins_with("Match3_"), "Instance ID has correct format")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.instance_id.begins_with("Match3_"), "Instance ID has correct format"
|
||||
)
|
||||
|
||||
|
||||
func test_match_detection():
|
||||
TestHelper.print_step("Match Detection Logic")
|
||||
@@ -205,9 +264,15 @@ func test_match_detection():
|
||||
return
|
||||
|
||||
# Test match detection methods exist and can be called safely
|
||||
TestHelper.assert_true(match3_instance.has_method("_has_match_at"), "_has_match_at method exists")
|
||||
TestHelper.assert_true(match3_instance.has_method("_check_for_matches"), "_check_for_matches method exists")
|
||||
TestHelper.assert_true(match3_instance.has_method("_get_match_line"), "_get_match_line method exists")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_method("_has_match_at"), "_has_match_at method exists"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_method("_check_for_matches"), "_check_for_matches method exists"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_method("_get_match_line"), "_get_match_line method exists"
|
||||
)
|
||||
|
||||
# Test boundary checking with invalid positions
|
||||
var invalid_positions = [
|
||||
@@ -227,7 +292,10 @@ func test_match_detection():
|
||||
for x in range(min(3, match3_instance.GRID_SIZE.x)):
|
||||
var pos = Vector2i(x, y)
|
||||
var result = match3_instance._has_match_at(pos)
|
||||
TestHelper.assert_true(result is bool, "Valid position (%d,%d) returns boolean" % [x, y])
|
||||
TestHelper.assert_true(
|
||||
result is bool, "Valid position (%d,%d) returns boolean" % [x, y]
|
||||
)
|
||||
|
||||
|
||||
func test_scoring_system():
|
||||
TestHelper.print_step("Scoring System")
|
||||
@@ -239,18 +307,17 @@ func test_scoring_system():
|
||||
# The scoring system uses: 3 gems = 3 points, 4+ gems = n + (n-2) points
|
||||
|
||||
# Test that the match3 instance can handle scoring (indirectly through clearing matches)
|
||||
TestHelper.assert_true(match3_instance.has_method("_clear_matches"), "Scoring system method exists")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_method("_clear_matches"), "Scoring system method exists"
|
||||
)
|
||||
|
||||
# Test that score_changed signal exists
|
||||
TestHelper.assert_true(match3_instance.has_signal("score_changed"), "Score changed signal exists")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_signal("score_changed"), "Score changed signal exists"
|
||||
)
|
||||
|
||||
# Test scoring formula logic (based on the documented formula)
|
||||
var test_scores = {
|
||||
3: 3, # 3 gems = exactly 3 points
|
||||
4: 6, # 4 gems = 4 + (4-2) = 6 points
|
||||
5: 8, # 5 gems = 5 + (5-2) = 8 points
|
||||
6: 10 # 6 gems = 6 + (6-2) = 10 points
|
||||
}
|
||||
var test_scores = {3: 3, 4: 6, 5: 8, 6: 10} # 3 gems = exactly 3 points # 4 gems = 4 + (4-2) = 6 points # 5 gems = 5 + (5-2) = 8 points # 6 gems = 6 + (6-2) = 10 points
|
||||
|
||||
for match_size in test_scores.keys():
|
||||
var expected_score = test_scores[match_size]
|
||||
@@ -260,7 +327,10 @@ func test_scoring_system():
|
||||
else:
|
||||
calculated_score = match_size + max(0, match_size - 2)
|
||||
|
||||
TestHelper.assert_equal(expected_score, calculated_score, "Scoring formula correct for %d gems" % match_size)
|
||||
TestHelper.assert_equal(
|
||||
expected_score, calculated_score, "Scoring formula correct for %d gems" % match_size
|
||||
)
|
||||
|
||||
|
||||
func test_input_validation():
|
||||
TestHelper.print_step("Input Validation")
|
||||
@@ -270,16 +340,25 @@ func test_input_validation():
|
||||
|
||||
# Test cursor position bounds
|
||||
TestHelper.assert_not_null(match3_instance.cursor_position, "Cursor position is initialized")
|
||||
TestHelper.assert_true(match3_instance.cursor_position is Vector2i, "Cursor position is Vector2i type")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.cursor_position is Vector2i, "Cursor position is Vector2i type"
|
||||
)
|
||||
|
||||
# Test keyboard navigation flag
|
||||
TestHelper.assert_true("keyboard_navigation_enabled" in match3_instance, "Keyboard navigation flag exists")
|
||||
TestHelper.assert_true(match3_instance.keyboard_navigation_enabled is bool, "Keyboard navigation flag is boolean")
|
||||
TestHelper.assert_true(
|
||||
"keyboard_navigation_enabled" in match3_instance, "Keyboard navigation flag exists"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
match3_instance.keyboard_navigation_enabled is bool, "Keyboard navigation flag is boolean"
|
||||
)
|
||||
|
||||
# Test selected tile safety
|
||||
# selected_tile can be null initially, which is valid
|
||||
if match3_instance.selected_tile:
|
||||
TestHelper.assert_true(is_instance_valid(match3_instance.selected_tile), "Selected tile is valid if not null")
|
||||
TestHelper.assert_true(
|
||||
is_instance_valid(match3_instance.selected_tile), "Selected tile is valid if not null"
|
||||
)
|
||||
|
||||
|
||||
func test_memory_safety():
|
||||
TestHelper.print_step("Memory Safety")
|
||||
@@ -288,23 +367,33 @@ func test_memory_safety():
|
||||
return
|
||||
|
||||
# Test grid integrity validation
|
||||
TestHelper.assert_true(match3_instance.has_method("_validate_grid_integrity"), "Grid integrity validation method exists")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_method("_validate_grid_integrity"),
|
||||
"Grid integrity validation method exists"
|
||||
)
|
||||
|
||||
# Test tile validity checking
|
||||
for y in range(min(3, match3_instance.grid.size())):
|
||||
for x in range(min(3, match3_instance.grid[y].size())):
|
||||
var tile = match3_instance.grid[y][x]
|
||||
if tile:
|
||||
TestHelper.assert_true(is_instance_valid(tile), "Grid tile at (%d,%d) is valid instance" % [x, y])
|
||||
TestHelper.assert_true(tile.get_parent() == match3_instance, "Tile properly parented to Match3")
|
||||
TestHelper.assert_true(
|
||||
is_instance_valid(tile), "Grid tile at (%d,%d) is valid instance" % [x, y]
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
tile.get_parent() == match3_instance, "Tile properly parented to Match3"
|
||||
)
|
||||
|
||||
# Test position validation
|
||||
TestHelper.assert_true(match3_instance.has_method("_is_valid_grid_position"), "Position validation method exists")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.has_method("_is_valid_grid_position"), "Position validation method exists"
|
||||
)
|
||||
|
||||
# Test safe tile access patterns exist
|
||||
# The Match3 code uses comprehensive bounds checking and null validation
|
||||
TestHelper.assert_true(true, "Memory safety patterns implemented in Match3 code")
|
||||
|
||||
|
||||
func test_performance_requirements():
|
||||
TestHelper.print_step("Performance Requirements")
|
||||
|
||||
@@ -316,12 +405,22 @@ func test_performance_requirements():
|
||||
TestHelper.assert_true(total_tiles <= 225, "Total tiles within performance limit (15x15=225)")
|
||||
|
||||
# Test cascade iteration limit prevents infinite loops
|
||||
TestHelper.assert_equal(20, match3_instance.MAX_CASCADE_ITERATIONS, "Cascade iteration limit prevents infinite loops")
|
||||
TestHelper.assert_equal(
|
||||
20,
|
||||
match3_instance.MAX_CASCADE_ITERATIONS,
|
||||
"Cascade iteration limit prevents infinite loops"
|
||||
)
|
||||
|
||||
# Test timing constants are reasonable for 60fps gameplay
|
||||
TestHelper.assert_true(match3_instance.CASCADE_WAIT_TIME >= 0.05, "Cascade wait time allows for smooth animation")
|
||||
TestHelper.assert_true(match3_instance.SWAP_ANIMATION_TIME <= 0.5, "Swap animation time is responsive")
|
||||
TestHelper.assert_true(match3_instance.TILE_DROP_WAIT_TIME <= 0.3, "Tile drop wait time is responsive")
|
||||
TestHelper.assert_true(
|
||||
match3_instance.CASCADE_WAIT_TIME >= 0.05, "Cascade wait time allows for smooth animation"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
match3_instance.SWAP_ANIMATION_TIME <= 0.5, "Swap animation time is responsive"
|
||||
)
|
||||
TestHelper.assert_true(
|
||||
match3_instance.TILE_DROP_WAIT_TIME <= 0.3, "Tile drop wait time is responsive"
|
||||
)
|
||||
|
||||
# Test grid initialization performance
|
||||
TestHelper.start_performance_test("grid_access")
|
||||
@@ -332,6 +431,7 @@ func test_performance_requirements():
|
||||
var tile_type = tile.tile_type
|
||||
TestHelper.end_performance_test("grid_access", 10.0, "Grid access performance within limits")
|
||||
|
||||
|
||||
func cleanup_tests():
|
||||
TestHelper.print_step("Cleanup")
|
||||
|
||||
@@ -346,4 +446,4 @@ func cleanup_tests():
|
||||
# Wait for cleanup
|
||||
await process_frame
|
||||
|
||||
TestHelper.assert_true(true, "Test cleanup completed")
|
||||
TestHelper.assert_true(true, "Test cleanup completed")
|
||||
|
||||
Reference in New Issue
Block a user