Add and update name convention
Some checks failed
Some checks failed
This commit is contained in:
@@ -4,9 +4,10 @@
|
|||||||
"WebSearch",
|
"WebSearch",
|
||||||
"Bash(find:*)",
|
"Bash(find:*)",
|
||||||
"Bash(godot:*)",
|
"Bash(godot:*)",
|
||||||
"Bash(python:*)"
|
"Bash(python:*)",
|
||||||
|
"Bash(git mv:*)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,4 +6,4 @@
|
|||||||
- Use TDD methodology for development;
|
- Use TDD methodology for development;
|
||||||
- Use static data types;
|
- Use static data types;
|
||||||
- Keep documentation up to date;
|
- Keep documentation up to date;
|
||||||
- Always run gdlint, gdformat and run tests;
|
- Always run tests `tools\run_development.py --yaml --silent`;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ Guidance for Claude Code (claude.ai/code) when working with this repository.
|
|||||||
- Invalid swaps automatically revert after animation
|
- Invalid swaps automatically revert after animation
|
||||||
- State machine: WAITING → SELECTING → SWAPPING → PROCESSING
|
- State machine: WAITING → SELECTING → SWAPPING → PROCESSING
|
||||||
- Test scripts located in `tests/` directory for system validation
|
- Test scripts located in `tests/` directory for system validation
|
||||||
- Use `test_logging.gd` to validate the logging system functionality
|
- Use `TestLogging.gd` to validate the logging system functionality
|
||||||
|
|
||||||
### Audio Configuration
|
### Audio Configuration
|
||||||
- Music: Located in `assets/audio/music/` directory with loop configuration in AudioManager
|
- Music: Located in `assets/audio/music/` directory with loop configuration in AudioManager
|
||||||
@@ -111,7 +111,7 @@ Guidance for Claude Code (claude.ai/code) when working with this repository.
|
|||||||
- `src/autoloads/SettingsManager.gd` - Settings management with input validation and security
|
- `src/autoloads/SettingsManager.gd` - Settings management with input validation and security
|
||||||
- `src/autoloads/DebugManager.gd` - Debug system integration
|
- `src/autoloads/DebugManager.gd` - Debug system integration
|
||||||
- `scenes/game/game.gd` - Main game scene with modular gameplay system
|
- `scenes/game/game.gd` - Main game scene with modular gameplay system
|
||||||
- `scenes/game/gameplays/match3_gameplay.gd` - Match-3 implementation with input validation
|
- `scenes/game/gameplays/Match3Gameplay.gd` - Match-3 implementation with input validation
|
||||||
- `scenes/game/gameplays/tile.gd` - Instance-based tile behavior without global state
|
- `scenes/game/gameplays/tile.gd` - Instance-based tile behavior without global state
|
||||||
- `scenes/ui/DebugMenuBase.gd` - Unified debug menu base class
|
- `scenes/ui/DebugMenuBase.gd` - Unified debug menu base class
|
||||||
- `scenes/ui/SettingsMenu.gd` - Settings UI with input validation
|
- `scenes/ui/SettingsMenu.gd` - Settings UI with input validation
|
||||||
@@ -123,8 +123,9 @@ Guidance for Claude Code (claude.ai/code) when working with this repository.
|
|||||||
### Before Making Changes
|
### Before Making Changes
|
||||||
1. Check `docs/MAP.md` for architecture
|
1. Check `docs/MAP.md` for architecture
|
||||||
2. Review `docs/CODE_OF_CONDUCT.md` for coding standards
|
2. Review `docs/CODE_OF_CONDUCT.md` for coding standards
|
||||||
3. Understand existing patterns before implementing features
|
3. **Review naming conventions**: See [Naming Convention Quick Reference](CODE_OF_CONDUCT.md#naming-convention-quick-reference) for all file and code naming standards
|
||||||
4. If adding assets, prepare `assets/sources.yaml` documentation
|
4. Understand existing patterns before implementing features
|
||||||
|
5. If adding assets, prepare `assets/sources.yaml` documentation following [asset naming conventions](CODE_OF_CONDUCT.md#5-asset-file-naming)
|
||||||
|
|
||||||
### Testing Changes
|
### Testing Changes
|
||||||
- Run project with F5 in Godot Editor
|
- Run project with F5 in Godot Editor
|
||||||
@@ -132,10 +133,10 @@ Guidance for Claude Code (claude.ai/code) when working with this repository.
|
|||||||
- Verify scene transitions work
|
- Verify scene transitions work
|
||||||
- Check mobile compatibility if UI changes made
|
- Check mobile compatibility if UI changes made
|
||||||
- Use test scripts from `tests/` directory to validate functionality
|
- Use test scripts from `tests/` directory to validate functionality
|
||||||
- Run `test_logging.gd` after logging system changes
|
- Run `TestLogging.gd` after logging system changes
|
||||||
- **Save system testing**: Run save/load test suites after SaveManager changes
|
- **Save system testing**: Run save/load test suites after SaveManager changes
|
||||||
- **Checksum validation**: Test `test_checksum_issue.gd` to verify deterministic checksums
|
- **Checksum validation**: Test `test_checksum_issue.gd` to verify deterministic checksums
|
||||||
- **Migration compatibility**: Run `test_migration_compatibility.gd` for version upgrades
|
- **Migration compatibility**: Run `TestMigrationCompatibility.gd` for version upgrades
|
||||||
|
|
||||||
### Common Implementation Patterns
|
### Common Implementation Patterns
|
||||||
- **Scene transitions**: Use `GameManager.start_game_with_mode()` with built-in validation
|
- **Scene transitions**: Use `GameManager.start_game_with_mode()` with built-in validation
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ Coding standards and development practices for the Skelly project. These guideli
|
|||||||
## GDScript Coding Standards
|
## GDScript Coding Standards
|
||||||
|
|
||||||
### Naming Conventions
|
### Naming Conventions
|
||||||
|
|
||||||
|
> 📋 **Quick Reference**: For complete naming convention details, see the **[Naming Convention Quick Reference](#naming-convention-quick-reference)** section below.
|
||||||
|
|
||||||
```gdscript
|
```gdscript
|
||||||
# Variables and functions: snake_case
|
# Variables and functions: snake_case
|
||||||
var player_health: int = 100
|
var player_health: int = 100
|
||||||
@@ -39,6 +42,11 @@ const TILE_SPACING := 54
|
|||||||
# Classes: PascalCase
|
# Classes: PascalCase
|
||||||
class_name PlayerController
|
class_name PlayerController
|
||||||
|
|
||||||
|
# Scene files (.tscn) and Script files (.gd): PascalCase
|
||||||
|
# MainMenu.tscn, MainMenu.gd
|
||||||
|
# Match3Gameplay.tscn, Match3Gameplay.gd
|
||||||
|
# TestAudioManager.gd (test files)
|
||||||
|
|
||||||
# Signals: past_tense
|
# Signals: past_tense
|
||||||
signal health_changed
|
signal health_changed
|
||||||
signal game_started
|
signal game_started
|
||||||
@@ -100,7 +108,7 @@ func _get_match_line(start: Vector2i, dir: Vector2i) -> Array:
|
|||||||
GameManager.start_match3_game()
|
GameManager.start_match3_game()
|
||||||
|
|
||||||
# ❌ Wrong
|
# ❌ Wrong
|
||||||
get_tree().change_scene_to_file("res://scenes/game.tscn")
|
get_tree().change_scene_to_file("res://scenes/game/Game.tscn")
|
||||||
```
|
```
|
||||||
|
|
||||||
### Autoload Usage
|
### Autoload Usage
|
||||||
@@ -263,6 +271,207 @@ wip
|
|||||||
- Verify debug state persists across scene changes
|
- Verify debug state persists across scene changes
|
||||||
- Check debug code doesn't affect release builds
|
- Check debug code doesn't affect release builds
|
||||||
|
|
||||||
|
## Naming Convention Quick Reference
|
||||||
|
|
||||||
|
> 🎯 **Single Source of Truth**: This section contains all naming conventions for the Skelly project. All other documentation files reference this section to avoid duplication and ensure consistency.
|
||||||
|
|
||||||
|
### 1. GDScript Code Elements
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
# Variables and functions: snake_case
|
||||||
|
var player_health: int = 100
|
||||||
|
func calculate_damage() -> int:
|
||||||
|
|
||||||
|
# Constants: SCREAMING_SNAKE_CASE
|
||||||
|
const MAX_HEALTH := 100
|
||||||
|
const TILE_SPACING := 54
|
||||||
|
|
||||||
|
# Classes: PascalCase
|
||||||
|
class_name PlayerController
|
||||||
|
|
||||||
|
# Signals: past_tense_with_underscores
|
||||||
|
signal health_changed
|
||||||
|
signal game_started
|
||||||
|
signal match_found
|
||||||
|
|
||||||
|
# Private functions: prefix with underscore
|
||||||
|
func _ready():
|
||||||
|
func _initialize_grid():
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. File Naming Standards
|
||||||
|
|
||||||
|
#### Script and Scene Files
|
||||||
|
```gdscript
|
||||||
|
# ✅ Correct: All .gd and .tscn files use PascalCase
|
||||||
|
MainMenu.tscn / MainMenu.gd
|
||||||
|
Match3Gameplay.tscn / Match3Gameplay.gd
|
||||||
|
ClickomaniaGameplay.tscn / ClickomaniaGameplay.gd
|
||||||
|
ValueStepper.tscn / ValueStepper.gd
|
||||||
|
|
||||||
|
# Test files: PascalCase with "Test" prefix
|
||||||
|
TestAudioManager.gd
|
||||||
|
TestGameManager.gd
|
||||||
|
TestMatch3Gameplay.gd
|
||||||
|
|
||||||
|
# ❌ Wrong: Old snake_case style (being migrated)
|
||||||
|
main_menu.tscn / main_menu.gd
|
||||||
|
TestAudioManager.gd
|
||||||
|
```
|
||||||
|
|
||||||
|
**Rules:**
|
||||||
|
- Scene files (.tscn) must match their script file name exactly
|
||||||
|
- All new files must use PascalCase
|
||||||
|
- Test files use "Test" prefix + PascalCase
|
||||||
|
- Autoload scripts follow PascalCase (GameManager.gd, AudioManager.gd)
|
||||||
|
|
||||||
|
### 3. Directory Naming Conventions
|
||||||
|
|
||||||
|
#### Source Code Directories
|
||||||
|
```
|
||||||
|
# Source directories: snake_case
|
||||||
|
src/autoloads/
|
||||||
|
scenes/game/gameplays/
|
||||||
|
scenes/ui/components/
|
||||||
|
tests/helpers/
|
||||||
|
|
||||||
|
# Root directories: lowercase
|
||||||
|
docs/
|
||||||
|
tests/
|
||||||
|
tools/
|
||||||
|
data/
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Asset Directories
|
||||||
|
```
|
||||||
|
# Asset directories: kebab-case
|
||||||
|
assets/audio-files/
|
||||||
|
assets/ui-sprites/
|
||||||
|
assets/game-textures/
|
||||||
|
assets/fonts/
|
||||||
|
localization/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Resource and Configuration Files
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Configuration files: lowercase with dots
|
||||||
|
project.godot
|
||||||
|
gdlintrc
|
||||||
|
.gdformatrc
|
||||||
|
.editorconfig
|
||||||
|
export_presets.cfg
|
||||||
|
|
||||||
|
# Godot resource files (.tres): PascalCase
|
||||||
|
data/DefaultBusLayout.tres
|
||||||
|
data/PlayerSaveData.tres
|
||||||
|
scenes/ui/DefaultTheme.tres
|
||||||
|
|
||||||
|
# Asset metadata: kebab-case
|
||||||
|
assets/asset-sources.yaml
|
||||||
|
assets/audio-files/audio-sources.yaml
|
||||||
|
assets/ui-sprites/sprite-sources.yaml
|
||||||
|
|
||||||
|
# Development files: kebab-case
|
||||||
|
requirements.txt
|
||||||
|
development-tools.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Asset File Naming
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Audio files: kebab-case in kebab-case directories
|
||||||
|
assets/audio-files/background-music.ogg
|
||||||
|
assets/audio-files/ui-sounds/button-click.wav
|
||||||
|
assets/audio-files/game-sounds/match-sound.wav
|
||||||
|
|
||||||
|
# Visual assets: kebab-case
|
||||||
|
assets/ui-sprites/main-menu-background.png
|
||||||
|
assets/game-textures/gem-blue.png
|
||||||
|
assets/fonts/main-ui-font.ttf
|
||||||
|
|
||||||
|
# Import settings: match the original file
|
||||||
|
background-music.ogg.import
|
||||||
|
button-click.wav.import
|
||||||
|
```
|
||||||
|
|
||||||
|
**Asset Rules:**
|
||||||
|
- All asset files use kebab-case
|
||||||
|
- Organized in kebab-case directories
|
||||||
|
- Import files automatically match asset names
|
||||||
|
- Document all assets in `asset-sources.yaml`
|
||||||
|
|
||||||
|
### 6. Git Workflow Conventions
|
||||||
|
|
||||||
|
#### Branch Naming
|
||||||
|
```bash
|
||||||
|
# Feature branches: feature/description-with-hyphens
|
||||||
|
feature/new-gameplay-mode
|
||||||
|
feature/settings-ui-improvement
|
||||||
|
feature/audio-system-upgrade
|
||||||
|
|
||||||
|
# Bug fixes: fix/description-with-hyphens
|
||||||
|
fix/tile-positioning-bug
|
||||||
|
fix/save-data-corruption
|
||||||
|
fix/debug-menu-visibility
|
||||||
|
|
||||||
|
# Refactoring: refactor/component-name
|
||||||
|
refactor/match3-input-system
|
||||||
|
refactor/autoload-structure
|
||||||
|
|
||||||
|
# Documentation: docs/section-name
|
||||||
|
docs/code-of-conduct-update
|
||||||
|
docs/api-documentation
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Commit Message Format
|
||||||
|
```bash
|
||||||
|
# Format: <type>: <description>
|
||||||
|
# Examples:
|
||||||
|
feat: add dark mode toggle to settings menu
|
||||||
|
fix: resolve tile swap animation timing issue
|
||||||
|
docs: update naming conventions in code of conduct
|
||||||
|
refactor: migrate print statements to DebugManager
|
||||||
|
test: add comprehensive match3 validation tests
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Quick Reference Summary
|
||||||
|
|
||||||
|
| File Type | Convention | Example |
|
||||||
|
|-----------|------------|---------|
|
||||||
|
| **GDScript Files** | PascalCase | `MainMenu.gd`, `AudioManager.gd` |
|
||||||
|
| **Scene Files** | PascalCase | `MainMenu.tscn`, `Match3Gameplay.tscn` |
|
||||||
|
| **Test Files** | Test + PascalCase | `TestAudioManager.gd` |
|
||||||
|
| **Variables/Functions** | snake_case | `player_health`, `calculate_damage()` |
|
||||||
|
| **Constants** | SCREAMING_SNAKE_CASE | `MAX_HEALTH`, `TILE_SPACING` |
|
||||||
|
| **Classes** | PascalCase | `class_name PlayerController` |
|
||||||
|
| **Signals** | past_tense | `health_changed`, `game_started` |
|
||||||
|
| **Directories** | snake_case (src) / kebab-case (assets) | `src/autoloads/`, `assets/audio-files/` |
|
||||||
|
| **Assets** | kebab-case | `background-music.ogg`, `gem-blue.png` |
|
||||||
|
| **Config Files** | lowercase.extension | `project.godot`, `.gdformatrc` |
|
||||||
|
| **Branches** | type/kebab-case | `feature/new-gameplay`, `fix/tile-bug` |
|
||||||
|
|
||||||
|
> ✅ **Status**: All major file naming inconsistencies have been resolved. The project now follows consistent PascalCase naming for all .gd and .tscn files.
|
||||||
|
|
||||||
|
### 8. File Renaming Migration Guide
|
||||||
|
|
||||||
|
When renaming files to follow conventions:
|
||||||
|
|
||||||
|
**Step-by-step procedure:**
|
||||||
|
1. **Use Git rename**: `git mv old_file.gd NewFile.gd` (preserves history)
|
||||||
|
2. **Update .tscn references**: Modify script path in scene files
|
||||||
|
3. **Update code references**: Search and replace all `preload()` and `load()` statements
|
||||||
|
4. **Update project.godot**: If file is referenced in autoloads or project settings
|
||||||
|
5. **Update documentation**: Search all .md files for old references
|
||||||
|
6. **Update test files**: Modify any test files that reference the renamed file
|
||||||
|
7. **Run validation**: Execute `gdlint`, `gdformat`, and project tests
|
||||||
|
8. **Verify in editor**: Load scenes in Godot editor to confirm everything works
|
||||||
|
|
||||||
|
**Tools for validation:**
|
||||||
|
- `python tools/run_development.py --test` - Run all tests
|
||||||
|
- `python tools/run_development.py --lint` - Check code quality
|
||||||
|
- `python tools/run_development.py --format` - Ensure consistent formatting
|
||||||
|
|
||||||
## Common Mistakes to Avoid
|
## Common Mistakes to Avoid
|
||||||
|
|
||||||
### Architecture Violations
|
### Architecture Violations
|
||||||
@@ -271,7 +480,7 @@ wip
|
|||||||
get_tree().change_scene_to_file("some_scene.tscn")
|
get_tree().change_scene_to_file("some_scene.tscn")
|
||||||
|
|
||||||
# Don't hardcode paths
|
# Don't hardcode paths
|
||||||
var tile = load("res://scenes/game/gameplays/tile.tscn")
|
var tile = load("res://scenes/game/gameplays/Tile.tscn")
|
||||||
|
|
||||||
# Don't ignore null checks
|
# Don't ignore null checks
|
||||||
var node = get_node("SomeNode")
|
var node = get_node("SomeNode")
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
This document outlines the code quality standards implemented in the Skelly project and provides guidelines for maintaining high-quality, reliable code.
|
This document outlines the code quality standards implemented in the Skelly project and provides guidelines for maintaining high-quality, reliable code.
|
||||||
|
|
||||||
|
> 📋 **Naming Standards**: All code follows the [Naming Convention Quick Reference](CODE_OF_CONDUCT.md#naming-convention-quick-reference) for consistent file, class, and variable naming.
|
||||||
|
|
||||||
## Overview of Improvements
|
## Overview of Improvements
|
||||||
|
|
||||||
A comprehensive code quality improvement was conducted to eliminate critical flaws, improve maintainability, and ensure production-ready reliability. The improvements focus on memory safety, error handling, architecture quality, and input validation.
|
A comprehensive code quality improvement was conducted to eliminate critical flaws, improve maintainability, and ensure production-ready reliability. The improvements focus on memory safety, error handling, architecture quality, and input validation.
|
||||||
@@ -28,7 +30,7 @@ for child in children_to_remove:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Files Improved:**
|
**Files Improved:**
|
||||||
- `scenes/game/gameplays/match3_gameplay.gd`
|
- `scenes/game/gameplays/Match3Gameplay.gd`
|
||||||
- `scenes/game/gameplays/tile.gd`
|
- `scenes/game/gameplays/tile.gd`
|
||||||
|
|
||||||
### 2. Error Handling & Recovery
|
### 2. Error Handling & Recovery
|
||||||
@@ -111,7 +113,7 @@ static func set_active_gem_pool(gem_indices: Array) -> void:
|
|||||||
|
|
||||||
**Files Improved:**
|
**Files Improved:**
|
||||||
- `scenes/game/gameplays/tile.gd`
|
- `scenes/game/gameplays/tile.gd`
|
||||||
- `scenes/game/gameplays/match3_gameplay.gd`
|
- `scenes/game/gameplays/Match3Gameplay.gd`
|
||||||
|
|
||||||
## 🟡 Code Quality Improvements
|
## 🟡 Code Quality Improvements
|
||||||
|
|
||||||
@@ -173,7 +175,7 @@ func _move_cursor(direction: Vector2i) -> void:
|
|||||||
|
|
||||||
**Files Improved:**
|
**Files Improved:**
|
||||||
- `scenes/ui/SettingsMenu.gd`
|
- `scenes/ui/SettingsMenu.gd`
|
||||||
- `scenes/game/gameplays/match3_gameplay.gd`
|
- `scenes/game/gameplays/Match3Gameplay.gd`
|
||||||
- `src/autoloads/GameManager.gd`
|
- `src/autoloads/GameManager.gd`
|
||||||
|
|
||||||
## Development Standards
|
## Development Standards
|
||||||
|
|||||||
14
docs/MAP.md
14
docs/MAP.md
@@ -3,6 +3,8 @@
|
|||||||
## Overview
|
## Overview
|
||||||
Skelly is a Godot 4.4 game project featuring multiple gameplay modes. The project supports match-3 puzzle gameplay with planned clickomania gameplay through a modular gameplay architecture. It follows a modular structure with clear separation between scenes, autoloads, assets, and data.
|
Skelly is a Godot 4.4 game project featuring multiple gameplay modes. The project supports match-3 puzzle gameplay with planned clickomania gameplay through a modular gameplay architecture. It follows a modular structure with clear separation between scenes, autoloads, assets, and data.
|
||||||
|
|
||||||
|
> 📋 **Naming Conventions**: All file and directory naming follows the standards defined in [Naming Convention Quick Reference](CODE_OF_CONDUCT.md#naming-convention-quick-reference).
|
||||||
|
|
||||||
## Project Root Structure
|
## Project Root Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -150,8 +152,8 @@ The game now uses a modular gameplay architecture where different game modes can
|
|||||||
|
|
||||||
### Current Gameplay Modes
|
### Current Gameplay Modes
|
||||||
|
|
||||||
#### Match-3 Mode (`scenes/game/gameplays/match3_gameplay.tscn`)
|
#### Match-3 Mode (`scenes/game/gameplays/Match3Gameplay.tscn`)
|
||||||
1. **Match3 Controller** (`scenes/game/gameplays/match3_gameplay.gd`)
|
1. **Match3 Controller** (`scenes/game/gameplays/Match3Gameplay.gd`)
|
||||||
- Grid management (8x8 default) with memory-safe node cleanup
|
- Grid management (8x8 default) with memory-safe node cleanup
|
||||||
- Match detection algorithms with bounds checking and validation
|
- Match detection algorithms with bounds checking and validation
|
||||||
- Tile dropping and refilling with signal connections
|
- Tile dropping and refilling with signal connections
|
||||||
@@ -178,7 +180,7 @@ The game now uses a modular gameplay architecture where different game modes can
|
|||||||
- Smooth animations with Tween system
|
- Smooth animations with Tween system
|
||||||
- **Memory Safety**: Resource management and cleanup
|
- **Memory Safety**: Resource management and cleanup
|
||||||
|
|
||||||
#### Clickomania Mode (`scenes/game/gameplays/clickomania_gameplay.tscn`)
|
#### Clickomania Mode (`scenes/game/gameplays/ClickomaniaGameplay.tscn`)
|
||||||
- Planned implementation for clickomania-style gameplay
|
- Planned implementation for clickomania-style gameplay
|
||||||
- Will integrate with same scoring and UI systems as match-3
|
- Will integrate with same scoring and UI systems as match-3
|
||||||
|
|
||||||
@@ -262,9 +264,9 @@ sprites:
|
|||||||
- `MainStrings.ru.translation` - Russian translations
|
- `MainStrings.ru.translation` - Russian translations
|
||||||
|
|
||||||
### Testing & Validation (`tests/`)
|
### Testing & Validation (`tests/`)
|
||||||
- `test_logging.gd` - DebugManager logging system validation
|
- `TestLogging.gd` - DebugManager logging system validation
|
||||||
- **`test_checksum_issue.gd`** - SaveManager checksum validation and deterministic hashing
|
- **`test_checksum_issue.gd`** - SaveManager checksum validation and deterministic hashing
|
||||||
- **`test_migration_compatibility.gd`** - SaveManager version migration and backward compatibility
|
- **`TestMigrationCompatibility.gd`** - SaveManager version migration and backward compatibility
|
||||||
- **`test_save_system_integration.gd`** - Complete save/load workflow integration testing
|
- **`test_save_system_integration.gd`** - Complete save/load workflow integration testing
|
||||||
- **`test_checksum_fix_verification.gd`** - JSON serialization checksum fix verification
|
- **`test_checksum_fix_verification.gd`** - JSON serialization checksum fix verification
|
||||||
- `README.md` - Brief directory overview (see docs/TESTING.md for full guidelines)
|
- `README.md` - Brief directory overview (see docs/TESTING.md for full guidelines)
|
||||||
@@ -296,7 +298,7 @@ GameManager --> main.tscn, game.tscn
|
|||||||
GameManager --> scenes/game/gameplays/*.tscn (via GAMEPLAY_SCENES constant)
|
GameManager --> scenes/game/gameplays/*.tscn (via GAMEPLAY_SCENES constant)
|
||||||
Main --> MainMenu.tscn, SettingsMenu.tscn
|
Main --> MainMenu.tscn, SettingsMenu.tscn
|
||||||
Game --> GameplayContainer (dynamic loading of gameplay scenes)
|
Game --> GameplayContainer (dynamic loading of gameplay scenes)
|
||||||
Game --> scenes/game/gameplays/match3_gameplay.tscn, clickomania_gameplay.tscn
|
Game --> scenes/game/gameplays/Match3Gameplay.tscn, ClickomaniaGameplay.tscn
|
||||||
```
|
```
|
||||||
|
|
||||||
### Asset Dependencies
|
### Asset Dependencies
|
||||||
|
|||||||
@@ -11,9 +11,11 @@ The `tests/` directory contains:
|
|||||||
- Performance benchmarks
|
- Performance benchmarks
|
||||||
- Debugging tools
|
- Debugging tools
|
||||||
|
|
||||||
|
> 📋 **File Naming**: All test files follow the [naming conventions](CODE_OF_CONDUCT.md#2-file-naming-standards) with PascalCase and "Test" prefix (e.g., `TestAudioManager.gd`).
|
||||||
|
|
||||||
## Current Test Files
|
## Current Test Files
|
||||||
|
|
||||||
### `test_logging.gd`
|
### `TestLogging.gd`
|
||||||
Test script for DebugManager logging system.
|
Test script for DebugManager logging system.
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
@@ -26,10 +28,10 @@ Test script for DebugManager logging system.
|
|||||||
**Usage:**
|
**Usage:**
|
||||||
```gdscript
|
```gdscript
|
||||||
# Option 1: Add as temporary autoload
|
# Option 1: Add as temporary autoload
|
||||||
# In project.godot, add: tests/test_logging.gd
|
# In project.godot, add: tests/TestLogging.gd
|
||||||
|
|
||||||
# Option 2: Instantiate in a scene
|
# Option 2: Instantiate in a scene
|
||||||
var test_script = preload("res://tests/test_logging.gd").new()
|
var test_script = preload("res://tests/TestLogging.gd").new()
|
||||||
add_child(test_script)
|
add_child(test_script)
|
||||||
|
|
||||||
# Option 3: Run directly from editor
|
# Option 3: Run directly from editor
|
||||||
@@ -49,7 +51,7 @@ Follow these conventions for new test files:
|
|||||||
|
|
||||||
### File Naming
|
### File Naming
|
||||||
- Use descriptive names starting with `test_`
|
- Use descriptive names starting with `test_`
|
||||||
- Example: `test_audio_manager.gd`, `test_scene_transitions.gd`
|
- Example: `TestAudioManager.gd`, `test_scene_transitions.gd`
|
||||||
|
|
||||||
### File Structure
|
### File Structure
|
||||||
```gdscript
|
```gdscript
|
||||||
@@ -104,20 +106,20 @@ func test_error_conditions():
|
|||||||
|
|
||||||
### System Tests
|
### System Tests
|
||||||
Test core autoload managers and global systems:
|
Test core autoload managers and global systems:
|
||||||
- `test_logging.gd` - DebugManager logging system
|
- `TestLogging.gd` - DebugManager logging system
|
||||||
- `test_checksum_issue.gd` - SaveManager checksum validation and deterministic hashing
|
- `test_checksum_issue.gd` - SaveManager checksum validation and deterministic hashing
|
||||||
- `test_migration_compatibility.gd` - SaveManager version migration and backward compatibility
|
- `TestMigrationCompatibility.gd` - SaveManager version migration and backward compatibility
|
||||||
- `test_save_system_integration.gd` - Complete save/load workflow integration testing
|
- `test_save_system_integration.gd` - Complete save/load workflow integration testing
|
||||||
- `test_checksum_fix_verification.gd` - Verification of JSON serialization checksum fixes
|
- `test_checksum_fix_verification.gd` - Verification of JSON serialization checksum fixes
|
||||||
- `test_settings_manager.gd` - SettingsManager security validation, input validation, and error handling
|
- `TestSettingsManager.gd` - SettingsManager security validation, input validation, and error handling
|
||||||
- `test_game_manager.gd` - GameManager scene transitions, race condition protection, and input validation
|
- `TestGameManager.gd` - GameManager scene transitions, race condition protection, and input validation
|
||||||
- `test_audio_manager.gd` - AudioManager functionality, resource loading, and volume management
|
- `TestAudioManager.gd` - AudioManager functionality, resource loading, and volume management
|
||||||
|
|
||||||
### Component Tests
|
### Component Tests
|
||||||
Test individual game components:
|
Test individual game components:
|
||||||
- `test_match3_gameplay.gd` - Match-3 gameplay mechanics, grid management, and match detection
|
- `TestMatch3Gameplay.gd` - Match-3 gameplay mechanics, grid management, and match detection
|
||||||
- `test_tile.gd` - Tile component behavior, visual feedback, and memory safety
|
- `TestTile.gd` - Tile component behavior, visual feedback, and memory safety
|
||||||
- `test_value_stepper.gd` - ValueStepper UI component functionality and settings integration
|
- `TestValueStepper.gd` - ValueStepper UI component functionality and settings integration
|
||||||
|
|
||||||
### Integration Tests
|
### Integration Tests
|
||||||
Test system interactions and workflows:
|
Test system interactions and workflows:
|
||||||
@@ -135,7 +137,7 @@ SaveManager implements security features requiring testing for modifications.
|
|||||||
**Tests**: Checksum generation, JSON serialization consistency, save/load cycles
|
**Tests**: Checksum generation, JSON serialization consistency, save/load cycles
|
||||||
**Usage**: Run after checksum algorithm changes
|
**Usage**: Run after checksum algorithm changes
|
||||||
|
|
||||||
#### **`test_migration_compatibility.gd`** - Version Migration
|
#### **`TestMigrationCompatibility.gd`** - Version Migration
|
||||||
**Tests**: Backward compatibility, missing field addition, data structure normalization
|
**Tests**: Backward compatibility, missing field addition, data structure normalization
|
||||||
**Usage**: Test save format upgrades
|
**Usage**: Test save format upgrades
|
||||||
|
|
||||||
@@ -164,7 +166,7 @@ SaveManager implements security features requiring testing for modifications.
|
|||||||
|
|
||||||
#### **Test Sequence After Modifications**
|
#### **Test Sequence After Modifications**
|
||||||
1. `test_checksum_issue.gd` - Verify checksum consistency
|
1. `test_checksum_issue.gd` - Verify checksum consistency
|
||||||
2. `test_migration_compatibility.gd` - Check version upgrades
|
2. `TestMigrationCompatibility.gd` - Check version upgrades
|
||||||
3. `test_save_system_integration.gd` - Validate workflow
|
3. `test_save_system_integration.gd` - Validate workflow
|
||||||
4. Manual testing with corrupted files
|
4. Manual testing with corrupted files
|
||||||
5. Performance validation
|
5. Performance validation
|
||||||
@@ -182,7 +184,7 @@ godot --headless --script tests/test_checksum_issue.gd
|
|||||||
|
|
||||||
# Run all save system tests
|
# Run all save system tests
|
||||||
godot --headless --script tests/test_checksum_issue.gd
|
godot --headless --script tests/test_checksum_issue.gd
|
||||||
godot --headless --script tests/test_migration_compatibility.gd
|
godot --headless --script tests/TestMigrationCompatibility.gd
|
||||||
godot --headless --script tests/test_save_system_integration.gd
|
godot --headless --script tests/test_save_system_integration.gd
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -200,7 +202,7 @@ For CI/CD integration:
|
|||||||
- name: Run Test Suite
|
- name: Run Test Suite
|
||||||
run: |
|
run: |
|
||||||
godot --headless --script tests/test_checksum_issue.gd
|
godot --headless --script tests/test_checksum_issue.gd
|
||||||
godot --headless --script tests/test_migration_compatibility.gd
|
godot --headless --script tests/TestMigrationCompatibility.gd
|
||||||
# Add other tests as needed
|
# Add other tests as needed
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
const GAMEPLAY_SCENES = {
|
const GAMEPLAY_SCENES = {
|
||||||
"match3": "res://scenes/game/gameplays/match3_gameplay.tscn",
|
"match3": "res://scenes/game/gameplays/Match3Gameplay.tscn",
|
||||||
"clickomania": "res://scenes/game/gameplays/clickomania_gameplay.tscn"
|
"clickomania": "res://scenes/game/gameplays/ClickomaniaGameplay.tscn"
|
||||||
}
|
}
|
||||||
|
|
||||||
var current_gameplay_mode: String
|
var current_gameplay_mode: String
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
[gd_scene load_steps=4 format=3 uid="uid://dmwkyeq2l7u04"]
|
[gd_scene load_steps=4 format=3 uid="uid://8c2w55brpwmm"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://bs4veuda3h358" path="res://scenes/game/game.gd" id="1_uwrxv"]
|
[ext_resource type="Script" uid="uid://bs4veuda3h358" path="res://scenes/game/game.gd" id="1_uwrxv"]
|
||||||
[ext_resource type="PackedScene" path="res://scenes/ui/DebugToggle.tscn" id="3_debug"]
|
[ext_resource type="PackedScene" path="res://scenes/ui/DebugToggle.tscn" id="3_debug"]
|
||||||
|
|||||||
1
scenes/game/gameplays/ClickomaniaGameplay.gd.uid
Normal file
1
scenes/game/gameplays/ClickomaniaGameplay.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bkheckv0upd82
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://cl7g8v0eh3mam"]
|
[gd_scene load_steps=2 format=3 uid="uid://cl7g8v0eh3mam"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scenes/game/gameplays/clickomania_gameplay.gd" id="1_script"]
|
[ext_resource type="Script" path="res://scenes/game/gameplays/ClickomaniaGameplay.gd" id="1_script"]
|
||||||
|
|
||||||
[node name="Clickomania" type="Node2D"]
|
[node name="Clickomania" type="Node2D"]
|
||||||
script = ExtResource("1_script")
|
script = ExtResource("1_script")
|
||||||
@@ -4,7 +4,7 @@ extends DebugMenuBase
|
|||||||
func _ready():
|
func _ready():
|
||||||
# Set specific configuration for Match3DebugMenu
|
# Set specific configuration for Match3DebugMenu
|
||||||
log_category = "Match3"
|
log_category = "Match3"
|
||||||
target_script_path = "res://scenes/game/gameplays/match3_gameplay.gd"
|
target_script_path = "res://scenes/game/gameplays/Match3Gameplay.gd"
|
||||||
|
|
||||||
# Call parent's _ready
|
# Call parent's _ready
|
||||||
super()
|
super()
|
||||||
|
|||||||
1
scenes/game/gameplays/Match3Gameplay.gd.uid
Normal file
1
scenes/game/gameplays/Match3Gameplay.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dbbi8ooysxp7f
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[gd_scene load_steps=3 format=3 uid="uid://b4kv7g7kllwgb"]
|
[gd_scene load_steps=3 format=3 uid="uid://b4kv7g7kllwgb"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://o8crf6688lan" path="res://scenes/game/gameplays/match3_gameplay.gd" id="1_mvfdp"]
|
[ext_resource type="Script" uid="uid://o8crf6688lan" path="res://scenes/game/gameplays/Match3Gameplay.gd" id="1_mvfdp"]
|
||||||
[ext_resource type="PackedScene" uid="uid://b76oiwlifikl3" path="res://scenes/game/gameplays/Match3DebugMenu.tscn" id="2_debug_menu"]
|
[ext_resource type="PackedScene" uid="uid://b76oiwlifikl3" path="res://scenes/game/gameplays/Match3DebugMenu.tscn" id="2_debug_menu"]
|
||||||
|
|
||||||
[node name="Match3" type="Node2D"]
|
[node name="Match3" type="Node2D"]
|
||||||
1
scenes/game/gameplays/Match3InputHandler.gd.uid
Normal file
1
scenes/game/gameplays/Match3InputHandler.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://ogm8w7l6bhif
|
||||||
1
scenes/game/gameplays/Match3SaveManager.gd.uid
Normal file
1
scenes/game/gameplays/Match3SaveManager.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://duheejfr6de6x
|
||||||
1
scenes/game/gameplays/Match3Validator.gd.uid
Normal file
1
scenes/game/gameplays/Match3Validator.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dy3aym6riijct
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://bapywtqdghjqp
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
[gd_scene load_steps=5 format=3 uid="uid://ci2gk11211n0d"]
|
[gd_scene load_steps=5 format=3 uid="uid://bwvq7u0mv5dku"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://rvuchiy0guv3" path="res://scenes/main/Main.gd" id="1_0wfyh"]
|
[ext_resource type="Script" uid="uid://rvuchiy0guv3" path="res://scenes/main/Main.gd" id="1_0wfyh"]
|
||||||
[ext_resource type="PackedScene" uid="uid://gbe1jarrwqsi" path="res://scenes/main/SplashScreen.tscn" id="1_o5qli"]
|
[ext_resource type="PackedScene" uid="uid://gbe1jarrwqsi" path="res://scenes/main/SplashScreen.tscn" id="1_o5qli"]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const MIN_GRID_SIZE := 3
|
|||||||
const MIN_TILE_TYPES := 3
|
const MIN_TILE_TYPES := 3
|
||||||
const SCENE_SEARCH_COOLDOWN := 0.5
|
const SCENE_SEARCH_COOLDOWN := 0.5
|
||||||
|
|
||||||
@export var target_script_path: String = "res://scenes/game/gameplays/match3_gameplay.gd"
|
@export var target_script_path: String = "res://scenes/game/gameplays/Match3Gameplay.gd"
|
||||||
@export var log_category: String = "DebugMenu"
|
@export var log_category: String = "DebugMenu"
|
||||||
|
|
||||||
var match3_scene: Node2D
|
var match3_scene: Node2D
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ For complete testing guidelines, conventions, and usage instructions, see:
|
|||||||
|
|
||||||
## Current Files
|
## Current Files
|
||||||
|
|
||||||
- `test_logging.gd` - Comprehensive logging system validation script
|
- `TestLogging.gd` - Comprehensive logging system validation script
|
||||||
|
|
||||||
## Quick Usage
|
## Quick Usage
|
||||||
|
|
||||||
```gdscript
|
```gdscript
|
||||||
# Add as temporary autoload or run in scene
|
# Add as temporary autoload or run in scene
|
||||||
var test_script = preload("res://tests/test_logging.gd").new()
|
var test_script = preload("res://tests/TestLogging.gd").new()
|
||||||
add_child(test_script)
|
add_child(test_script)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
1
tests/TestAudioManager.gd.uid
Normal file
1
tests/TestAudioManager.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bloix8dfixjem
|
||||||
1
tests/TestGameManager.gd.uid
Normal file
1
tests/TestGameManager.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://b0ua34ofjdirr
|
||||||
1
tests/TestLogging.gd.uid
Normal file
1
tests/TestLogging.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://brqb7heh3g0ja
|
||||||
@@ -50,7 +50,7 @@ func setup_test_environment():
|
|||||||
TestHelperClass.print_step("Test Environment Setup")
|
TestHelperClass.print_step("Test Environment Setup")
|
||||||
|
|
||||||
# Load Match3 scene
|
# Load Match3 scene
|
||||||
match3_scene = load("res://scenes/game/gameplays/match3_gameplay.tscn")
|
match3_scene = load("res://scenes/game/gameplays/Match3Gameplay.tscn")
|
||||||
TestHelperClass.assert_not_null(match3_scene, "Match3 scene loads successfully")
|
TestHelperClass.assert_not_null(match3_scene, "Match3 scene loads successfully")
|
||||||
|
|
||||||
# Create test viewport for isolated testing
|
# Create test viewport for isolated testing
|
||||||
1
tests/TestMatch3Gameplay.gd.uid
Normal file
1
tests/TestMatch3Gameplay.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://cmv4qyq0x0bvv
|
||||||
1
tests/TestMigrationCompatibility.gd.uid
Normal file
1
tests/TestMigrationCompatibility.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://graevpkmrau4
|
||||||
@@ -4,8 +4,8 @@ extends SceneTree
|
|||||||
## This test verifies that mouse input, hover events, and tile selection work correctly
|
## This test verifies that mouse input, hover events, and tile selection work correctly
|
||||||
|
|
||||||
# Preloaded scenes to avoid duplication
|
# Preloaded scenes to avoid duplication
|
||||||
const MATCH3_SCENE = preload("res://scenes/game/gameplays/match3_gameplay.tscn")
|
const MATCH3_SCENE = preload("res://scenes/game/gameplays/Match3Gameplay.tscn")
|
||||||
const TILE_SCENE = preload("res://scenes/game/gameplays/tile.tscn")
|
const TILE_SCENE = preload("res://scenes/game/gameplays/Tile.tscn")
|
||||||
|
|
||||||
|
|
||||||
func _initialize():
|
func _initialize():
|
||||||
@@ -34,12 +34,12 @@ func test_match3_scene_loading():
|
|||||||
print("Testing Match3 scene loading...")
|
print("Testing Match3 scene loading...")
|
||||||
|
|
||||||
if not MATCH3_SCENE:
|
if not MATCH3_SCENE:
|
||||||
print("❌ FAILED: Could not load match3_gameplay.tscn")
|
print("❌ FAILED: Could not load Match3Gameplay.tscn")
|
||||||
return
|
return
|
||||||
|
|
||||||
var match3_instance = MATCH3_SCENE.instantiate()
|
var match3_instance = MATCH3_SCENE.instantiate()
|
||||||
if not match3_instance:
|
if not match3_instance:
|
||||||
print("❌ FAILED: Could not instantiate match3_gameplay scene")
|
print("❌ FAILED: Could not instantiate Match3Gameplay scene")
|
||||||
return
|
return
|
||||||
|
|
||||||
root.add_child(match3_instance)
|
root.add_child(match3_instance)
|
||||||
1
tests/TestMouseSupport.gd.uid
Normal file
1
tests/TestMouseSupport.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://kdrhd734kdel
|
||||||
@@ -151,7 +151,7 @@ func test_critical_scenes():
|
|||||||
"res://scenes/main/main.tscn",
|
"res://scenes/main/main.tscn",
|
||||||
"res://scenes/game/game.tscn",
|
"res://scenes/game/game.tscn",
|
||||||
"res://scenes/ui/MainMenu.tscn",
|
"res://scenes/ui/MainMenu.tscn",
|
||||||
"res://scenes/game/gameplays/match3_gameplay.tscn"
|
"res://scenes/game/gameplays/Match3Gameplay.tscn"
|
||||||
]
|
]
|
||||||
|
|
||||||
for scene_path in critical_scenes:
|
for scene_path in critical_scenes:
|
||||||
1
tests/TestSceneValidation.gd.uid
Normal file
1
tests/TestSceneValidation.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dco5ddmpe5o74
|
||||||
1
tests/TestSettingsManager.gd.uid
Normal file
1
tests/TestSettingsManager.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://btqloxgb5460v
|
||||||
1
tests/TestTile.gd.uid
Normal file
1
tests/TestTile.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://cf6uxd4ewd7n8
|
||||||
1
tests/TestValueStepper.gd.uid
Normal file
1
tests/TestValueStepper.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://copuu5lcw562s
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://bo0vdi2uhl8bm
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cxoh80im7pak
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://bwygfhgn60iw3
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://b0jpu50jmbt7t
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cnhiygvadc13
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://gnepq3ww2d0a
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://b6kwoodf4xtfg
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://dopm8ivgucbgd
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://bdn1rf14bqwv4
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://cfofaihfhmh8q
|
|
||||||
@@ -11,6 +11,7 @@ Usage examples:
|
|||||||
python tools/run_development.py --ruff # Only Python format & lint
|
python tools/run_development.py --ruff # Only Python format & lint
|
||||||
python tools/run_development.py --validate # Only file validation
|
python tools/run_development.py --validate # Only file validation
|
||||||
python tools/run_development.py --validate --silent # Silent validation (only errors)
|
python tools/run_development.py --validate --silent # Silent validation (only errors)
|
||||||
|
python tools/run_development.py --naming # Only naming convention check
|
||||||
python tools/run_development.py --test --yaml # Test results in YAML format
|
python tools/run_development.py --test --yaml # Test results in YAML format
|
||||||
python tools/run_development.py --steps lint ruff test # Custom workflow
|
python tools/run_development.py --steps lint ruff test # Custom workflow
|
||||||
python tools/run_development.py --async-mode # Force async mode
|
python tools/run_development.py --async-mode # Force async mode
|
||||||
@@ -20,6 +21,7 @@ Features:
|
|||||||
- Python formatting & linting with Ruff (fast formatter + linter with auto-fix)
|
- Python formatting & linting with Ruff (fast formatter + linter with auto-fix)
|
||||||
- Test execution
|
- Test execution
|
||||||
- YAML, TOML, and JSON file validation (respects .gitignore)
|
- YAML, TOML, and JSON file validation (respects .gitignore)
|
||||||
|
- PascalCase naming convention checks for .tscn and .gd files
|
||||||
- Colored output and comprehensive error reporting
|
- Colored output and comprehensive error reporting
|
||||||
- Machine-readable YAML output for CI/CD integration
|
- Machine-readable YAML output for CI/CD integration
|
||||||
- **Async processing for significantly faster execution with multiple files**
|
- **Async processing for significantly faster execution with multiple files**
|
||||||
@@ -622,6 +624,57 @@ def validate_json_file(file_path: Path) -> Tuple[bool, str]:
|
|||||||
return False, f"Error reading file: {e}"
|
return False, f"Error reading file: {e}"
|
||||||
|
|
||||||
|
|
||||||
|
def check_naming_convention(file_path: Path) -> Tuple[bool, str]:
|
||||||
|
"""Check if file follows PascalCase naming convention for .tscn and .gd files."""
|
||||||
|
file_name = file_path.name
|
||||||
|
|
||||||
|
# Skip files that shouldn't follow PascalCase
|
||||||
|
if file_path.suffix not in [".tscn", ".gd"]:
|
||||||
|
return True, ""
|
||||||
|
|
||||||
|
# Skip certain directories and files
|
||||||
|
skip_dirs = {"autoloads", "helpers"}
|
||||||
|
if any(part in skip_dirs for part in file_path.parts):
|
||||||
|
return True, ""
|
||||||
|
|
||||||
|
# Skip project-specific files that are exempt
|
||||||
|
exempt_files = {
|
||||||
|
"project.godot",
|
||||||
|
"icon.svg",
|
||||||
|
"export_presets.cfg",
|
||||||
|
"default_bus_layout.tres",
|
||||||
|
}
|
||||||
|
if file_name in exempt_files:
|
||||||
|
return True, ""
|
||||||
|
|
||||||
|
# Check PascalCase pattern
|
||||||
|
name_without_ext = file_path.stem
|
||||||
|
|
||||||
|
# PascalCase: starts with capital letter, can have more capitals, no underscores or hyphens
|
||||||
|
if not re.match(r"^[A-Z][a-zA-Z0-9]*$", name_without_ext):
|
||||||
|
return (
|
||||||
|
False,
|
||||||
|
f"File name '{file_name}' should use PascalCase (e.g., 'MainMenu.gd', 'Match3Gameplay.tscn')",
|
||||||
|
)
|
||||||
|
|
||||||
|
return True, ""
|
||||||
|
|
||||||
|
|
||||||
|
def get_naming_files(project_root: Path) -> List[Path]:
|
||||||
|
"""Get all .tscn and .gd files that should follow naming conventions."""
|
||||||
|
files = []
|
||||||
|
for pattern in ["**/*.tscn", "**/*.gd"]:
|
||||||
|
files.extend(project_root.glob(pattern))
|
||||||
|
|
||||||
|
# Filter out files that should be ignored
|
||||||
|
filtered_files = []
|
||||||
|
for file_path in files:
|
||||||
|
if not should_skip_file(file_path):
|
||||||
|
filtered_files.append(file_path)
|
||||||
|
|
||||||
|
return filtered_files
|
||||||
|
|
||||||
|
|
||||||
async def validate_json_file_async(file_path: Path) -> Tuple[bool, str]:
|
async def validate_json_file_async(file_path: Path) -> Tuple[bool, str]:
|
||||||
"""Validate a JSON file asynchronously."""
|
"""Validate a JSON file asynchronously."""
|
||||||
if aiofiles is None:
|
if aiofiles is None:
|
||||||
@@ -1249,6 +1302,100 @@ async def run_validate_async(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_naming(
|
||||||
|
project_root: Path, silent: bool = False, yaml_output: bool = False
|
||||||
|
) -> Tuple[bool, Dict]:
|
||||||
|
"""Check naming conventions for .tscn and .gd files."""
|
||||||
|
if not silent and not yaml_output:
|
||||||
|
print_header("📝 Naming Convention Check")
|
||||||
|
|
||||||
|
# Get all files that should follow naming conventions
|
||||||
|
naming_files = get_naming_files(project_root)
|
||||||
|
total_files = len(naming_files)
|
||||||
|
|
||||||
|
if total_files == 0:
|
||||||
|
if not silent:
|
||||||
|
msg = "No .tscn or .gd files found to check naming conventions."
|
||||||
|
colored_msg = Colors.colorize(msg, Colors.YELLOW)
|
||||||
|
print(colored_msg)
|
||||||
|
return True, {"Total files": 0, "Valid files": 0, "Invalid files": 0}
|
||||||
|
|
||||||
|
if not silent and not yaml_output:
|
||||||
|
count_msg = f"Checking naming conventions for {total_files} files..."
|
||||||
|
colored_count = Colors.colorize(count_msg, Colors.BLUE)
|
||||||
|
print(colored_count)
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Process files
|
||||||
|
valid_files = 0
|
||||||
|
invalid_files = 0
|
||||||
|
all_output = []
|
||||||
|
|
||||||
|
for file_path in naming_files:
|
||||||
|
is_valid, error_msg = check_naming_convention(file_path)
|
||||||
|
relative_path = file_path.relative_to(project_root)
|
||||||
|
|
||||||
|
if is_valid:
|
||||||
|
valid_files += 1
|
||||||
|
if not silent and not yaml_output:
|
||||||
|
file_msg = f"📄 Checking: {relative_path}"
|
||||||
|
colored_file = Colors.colorize(file_msg, Colors.CYAN)
|
||||||
|
success_msg = " ✅ Follows PascalCase convention"
|
||||||
|
colored_success = Colors.colorize(success_msg, Colors.GREEN)
|
||||||
|
all_output.extend([file_msg, success_msg])
|
||||||
|
print(colored_file)
|
||||||
|
print(colored_success)
|
||||||
|
else:
|
||||||
|
invalid_files += 1
|
||||||
|
# Always show naming errors, even in silent mode
|
||||||
|
if not yaml_output:
|
||||||
|
file_msg = f"📄 Checking: {relative_path}"
|
||||||
|
colored_file = Colors.colorize(file_msg, Colors.CYAN)
|
||||||
|
error_msg_display = f" ❌ {error_msg}"
|
||||||
|
colored_error = Colors.colorize(error_msg_display, Colors.RED)
|
||||||
|
all_output.extend([file_msg, error_msg_display])
|
||||||
|
print(colored_file)
|
||||||
|
print(colored_error)
|
||||||
|
|
||||||
|
# Results summary
|
||||||
|
overall_success = invalid_files == 0
|
||||||
|
stats = {
|
||||||
|
"Total files": total_files,
|
||||||
|
"Valid files": valid_files,
|
||||||
|
"Invalid files": invalid_files,
|
||||||
|
}
|
||||||
|
|
||||||
|
if not silent and not yaml_output:
|
||||||
|
print()
|
||||||
|
if overall_success:
|
||||||
|
success_msg = "✅ All files follow PascalCase naming convention!"
|
||||||
|
colored_success = Colors.colorize(success_msg, Colors.GREEN)
|
||||||
|
print(colored_success)
|
||||||
|
else:
|
||||||
|
error_msg = f"❌ {invalid_files} file(s) don't follow PascalCase convention"
|
||||||
|
colored_error = Colors.colorize(error_msg, Colors.RED)
|
||||||
|
print(colored_error)
|
||||||
|
|
||||||
|
if yaml_output:
|
||||||
|
# Collect only failed files for YAML output (don't include all files)
|
||||||
|
failed_paths = []
|
||||||
|
|
||||||
|
for file_path in naming_files:
|
||||||
|
relative_path_str = str(file_path.relative_to(project_root))
|
||||||
|
is_valid, error_msg = check_naming_convention(file_path)
|
||||||
|
|
||||||
|
if not is_valid:
|
||||||
|
failed_paths.append(relative_path_str)
|
||||||
|
|
||||||
|
results = {
|
||||||
|
**stats, # Include stats at top level for consistency
|
||||||
|
"failed_paths": failed_paths, # For failed_items extraction
|
||||||
|
}
|
||||||
|
output_yaml_results("naming", results, overall_success)
|
||||||
|
|
||||||
|
return overall_success, stats
|
||||||
|
|
||||||
|
|
||||||
def run_format(
|
def run_format(
|
||||||
project_root: Path, silent: bool = False, yaml_output: bool = False
|
project_root: Path, silent: bool = False, yaml_output: bool = False
|
||||||
) -> Tuple[bool, Dict]:
|
) -> Tuple[bool, Dict]:
|
||||||
@@ -1476,7 +1623,7 @@ def discover_test_files(project_root: Path) -> List[Tuple[Path, str]]:
|
|||||||
for test_dir, prefix in test_dirs:
|
for test_dir, prefix in test_dirs:
|
||||||
test_path = project_root / test_dir
|
test_path = project_root / test_dir
|
||||||
if test_path.exists():
|
if test_path.exists():
|
||||||
for test_file in test_path.glob("test_*.gd"):
|
for test_file in test_path.glob("Test*.gd"):
|
||||||
test_files.append((test_file, prefix))
|
test_files.append((test_file, prefix))
|
||||||
|
|
||||||
return test_files
|
return test_files
|
||||||
@@ -1754,6 +1901,10 @@ def run_workflow(
|
|||||||
"📋 File format validation (yaml/toml/json)",
|
"📋 File format validation (yaml/toml/json)",
|
||||||
lambda root: run_validate(root, silent, yaml_output),
|
lambda root: run_validate(root, silent, yaml_output),
|
||||||
),
|
),
|
||||||
|
"naming": (
|
||||||
|
"📝 Naming convention check (PascalCase)",
|
||||||
|
lambda root: run_naming(root, silent, yaml_output),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
if not silent:
|
if not silent:
|
||||||
@@ -1903,6 +2054,12 @@ async def run_workflow_async(
|
|||||||
"📋 File format validation (yaml/toml/json)",
|
"📋 File format validation (yaml/toml/json)",
|
||||||
lambda root: run_validate_async(root, silent, yaml_output),
|
lambda root: run_validate_async(root, silent, yaml_output),
|
||||||
),
|
),
|
||||||
|
"naming": (
|
||||||
|
"📝 Naming convention check (PascalCase)",
|
||||||
|
lambda root: run_naming(
|
||||||
|
root, silent, yaml_output
|
||||||
|
), # Using sync version - lightweight
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
if not silent:
|
if not silent:
|
||||||
@@ -2017,8 +2174,8 @@ async def main_async():
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--steps",
|
"--steps",
|
||||||
nargs="+",
|
nargs="+",
|
||||||
choices=["lint", "format", "test", "validate", "ruff"],
|
choices=["lint", "format", "test", "validate", "ruff", "naming"],
|
||||||
default=["format", "lint", "ruff", "test", "validate"],
|
default=["format", "lint", "ruff", "test", "validate", "naming"],
|
||||||
help="Workflow steps to run",
|
help="Workflow steps to run",
|
||||||
)
|
)
|
||||||
parser.add_argument("--lint", action="store_true", help="Run GDScript linting")
|
parser.add_argument("--lint", action="store_true", help="Run GDScript linting")
|
||||||
@@ -2030,6 +2187,9 @@ async def main_async():
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--ruff", action="store_true", help="Run Python formatting & linting with ruff"
|
"--ruff", action="store_true", help="Run Python formatting & linting with ruff"
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--naming", action="store_true", help="Check PascalCase naming conventions"
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--silent",
|
"--silent",
|
||||||
"-s",
|
"-s",
|
||||||
@@ -2078,6 +2238,7 @@ async def main_async():
|
|||||||
root, args.silent, args.yaml
|
root, args.silent, args.yaml
|
||||||
),
|
),
|
||||||
"ruff": lambda root: run_ruff_async(root, args.silent, args.yaml),
|
"ruff": lambda root: run_ruff_async(root, args.silent, args.yaml),
|
||||||
|
"naming": lambda root: run_naming(root, args.silent, args.yaml),
|
||||||
}
|
}
|
||||||
success, _ = await step_funcs[steps[0]](project_root)
|
success, _ = await step_funcs[steps[0]](project_root)
|
||||||
else:
|
else:
|
||||||
@@ -2087,6 +2248,7 @@ async def main_async():
|
|||||||
"test": lambda root: run_tests(root, args.silent, args.yaml),
|
"test": lambda root: run_tests(root, args.silent, args.yaml),
|
||||||
"validate": lambda root: run_validate(root, args.silent, args.yaml),
|
"validate": lambda root: run_validate(root, args.silent, args.yaml),
|
||||||
"ruff": lambda root: run_ruff(root, args.silent, args.yaml),
|
"ruff": lambda root: run_ruff(root, args.silent, args.yaml),
|
||||||
|
"naming": lambda root: run_naming(root, args.silent, args.yaml),
|
||||||
}
|
}
|
||||||
success, _ = step_funcs[steps[0]](project_root)
|
success, _ = step_funcs[steps[0]](project_root)
|
||||||
else:
|
else:
|
||||||
@@ -2114,8 +2276,8 @@ def main():
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--steps",
|
"--steps",
|
||||||
nargs="+",
|
nargs="+",
|
||||||
choices=["lint", "format", "test", "validate", "ruff"],
|
choices=["lint", "format", "test", "validate", "ruff", "naming"],
|
||||||
default=["format", "lint", "ruff", "test", "validate"],
|
default=["format", "lint", "ruff", "test", "validate", "naming"],
|
||||||
help="Workflow steps to run",
|
help="Workflow steps to run",
|
||||||
)
|
)
|
||||||
parser.add_argument("--lint", action="store_true", help="Run GDScript linting")
|
parser.add_argument("--lint", action="store_true", help="Run GDScript linting")
|
||||||
@@ -2131,6 +2293,9 @@ def main():
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Run Python formatting & linting with ruff",
|
help="Run Python formatting & linting with ruff",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--naming", action="store_true", help="Check PascalCase naming conventions"
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--silent",
|
"--silent",
|
||||||
"-s",
|
"-s",
|
||||||
@@ -2173,6 +2338,7 @@ def main():
|
|||||||
"test": lambda root: run_tests(root, args.silent, args.yaml),
|
"test": lambda root: run_tests(root, args.silent, args.yaml),
|
||||||
"validate": lambda root: run_validate(root, args.silent, args.yaml),
|
"validate": lambda root: run_validate(root, args.silent, args.yaml),
|
||||||
"ruff": lambda root: run_ruff(root, args.silent, args.yaml),
|
"ruff": lambda root: run_ruff(root, args.silent, args.yaml),
|
||||||
|
"naming": lambda root: run_naming(root, args.silent, args.yaml),
|
||||||
}
|
}
|
||||||
success, _ = step_funcs[steps[0]](project_root)
|
success, _ = step_funcs[steps[0]](project_root)
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user