Add code quality checks and formatting configuration

- Introduced a .clang-format file to enforce Google C++ style guidelines across the codebase.
- Updated CMakeLists.txt to include custom targets for formatting and format-checking using clang-format.
- Added a quality_check.sh script to automate code quality checks, including formatting and static analysis with cppcheck.
- Enhanced CMakePresets.json with new macOS-specific configurations for ARM64 and universal binaries, improving build flexibility and support.
This commit is contained in:
scawful
2025-09-26 12:57:20 -04:00
parent ec207cae06
commit 22c960eaf3
5 changed files with 248 additions and 24 deletions

83
.clang-format Normal file
View File

@@ -0,0 +1,83 @@
# Google C/C++ Code Style settings
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
# Author: Kehan Xue, kehan.xue (at) gmail.com
Language: Cpp
BasedOnStyle: Google
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: None
AlignOperands: Align
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: Never # To avoid conflict, set this "Never" and each "if statement" should include brace when coding
AllowShortLambdasOnASingleLine: Inline
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterStruct: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: BeforeColon
ColumnLimit: 80
CompactNamespaces: false
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false # Make sure the * or & align on the left
EmptyLineBeforeAccessModifier: LogicalBlock
FixNamespaceComments: true
IncludeBlocks: Preserve
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 2
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PointerAlignment: Left
ReflowComments: false
# SeparateDefinitionBlocks: Always # Only support since clang-format 14
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: c++11
TabWidth: 4
UseTab: Never

View File

@@ -127,6 +127,26 @@ if (YAZE_BUILD_TESTS)
add_subdirectory(test) add_subdirectory(test)
endif() endif()
# Code quality targets
find_program(CLANG_FORMAT NAMES clang-format clang-format-14 clang-format-15 clang-format-16 clang-format-17 clang-format-18)
if(CLANG_FORMAT)
file(GLOB_RECURSE ALL_SOURCE_FILES
"${CMAKE_SOURCE_DIR}/src/*.cc"
"${CMAKE_SOURCE_DIR}/src/*.h"
"${CMAKE_SOURCE_DIR}/test/*.cc"
"${CMAKE_SOURCE_DIR}/test/*.h")
add_custom_target(format
COMMAND ${CLANG_FORMAT} -i --style=Google ${ALL_SOURCE_FILES}
COMMENT "Running clang-format on source files"
)
add_custom_target(format-check
COMMAND ${CLANG_FORMAT} --dry-run --Werror --style=Google ${ALL_SOURCE_FILES}
COMMENT "Checking code format"
)
endif()
# Packaging configuration # Packaging configuration
include(cmake/packaging.cmake) include(cmake/packaging.cmake)

View File

@@ -10,7 +10,7 @@
"name": "default", "name": "default",
"displayName": "Default Config", "displayName": "Default Config",
"description": "Default build configuration", "description": "Default build configuration",
"generator": "Ninja", "generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/build", "binaryDir": "${sourceDir}/build",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo", "CMAKE_BUILD_TYPE": "RelWithDebInfo",
@@ -52,6 +52,16 @@
"YAZE_TEST_ROM_PATH": "${sourceDir}/build/bin/zelda3.sfc" "YAZE_TEST_ROM_PATH": "${sourceDir}/build/bin/zelda3.sfc"
} }
}, },
{
"name": "macos-dev",
"displayName": "macOS Development (ARM64)",
"description": "macOS ARM64 development build with ROM testing",
"inherits": "macos-debug",
"cacheVariables": {
"YAZE_ENABLE_ROM_TESTS": "ON",
"YAZE_TEST_ROM_PATH": "${sourceDir}/build/bin/zelda3.sfc"
}
},
{ {
"name": "ci", "name": "ci",
"displayName": "Continuous Integration", "displayName": "Continuous Integration",
@@ -64,8 +74,38 @@
}, },
{ {
"name": "macos-debug", "name": "macos-debug",
"displayName": "macOS Debug", "displayName": "macOS Debug (ARM64)",
"description": "macOS-specific debug configuration", "description": "macOS ARM64-specific debug configuration",
"inherits": "debug",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"cacheVariables": {
"CMAKE_OSX_DEPLOYMENT_TARGET": "11.0",
"CMAKE_OSX_ARCHITECTURES": "arm64"
}
},
{
"name": "macos-release",
"displayName": "macOS Release (ARM64)",
"description": "macOS ARM64-specific release configuration",
"inherits": "release",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"cacheVariables": {
"CMAKE_OSX_DEPLOYMENT_TARGET": "11.0",
"CMAKE_OSX_ARCHITECTURES": "arm64"
}
},
{
"name": "macos-debug-universal",
"displayName": "macOS Debug (Universal)",
"description": "macOS universal binary debug configuration",
"inherits": "debug", "inherits": "debug",
"condition": { "condition": {
"type": "equals", "type": "equals",
@@ -78,9 +118,9 @@
} }
}, },
{ {
"name": "macos-release", "name": "macos-release-universal",
"displayName": "macOS Release", "displayName": "macOS Release (Universal)",
"description": "macOS-specific release configuration", "description": "macOS universal binary release configuration",
"inherits": "release", "inherits": "release",
"condition": { "condition": {
"type": "equals", "type": "equals",
@@ -184,6 +224,11 @@
"configurePreset": "dev", "configurePreset": "dev",
"displayName": "Development Build" "displayName": "Development Build"
}, },
{
"name": "macos-dev",
"configurePreset": "macos-dev",
"displayName": "macOS Development Build (ARM64)"
},
{ {
"name": "ci", "name": "ci",
"configurePreset": "ci", "configurePreset": "ci",
@@ -197,7 +242,17 @@
{ {
"name": "macos-release", "name": "macos-release",
"configurePreset": "macos-release", "configurePreset": "macos-release",
"displayName": "macOS Release Build" "displayName": "macOS Release Build (ARM64)"
},
{
"name": "macos-debug-universal",
"configurePreset": "macos-debug-universal",
"displayName": "macOS Debug Build (Universal)"
},
{
"name": "macos-release-universal",
"configurePreset": "macos-release-universal",
"displayName": "macOS Release Build (Universal)"
}, },
{ {
"name": "fast", "name": "fast",
@@ -293,7 +348,12 @@
{ {
"name": "macos", "name": "macos",
"configurePreset": "macos-release", "configurePreset": "macos-release",
"displayName": "macOS Package" "displayName": "macOS Package (ARM64)"
},
{
"name": "macos-universal",
"configurePreset": "macos-release-universal",
"displayName": "macOS Package (Universal)"
} }
], ],
"workflowPresets": [ "workflowPresets": [

54
scripts/quality_check.sh Executable file
View File

@@ -0,0 +1,54 @@
#!/bin/bash
# Quality check script for YAZE codebase
# This script runs various code quality checks to ensure CI/CD pipeline passes
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
cd "${PROJECT_ROOT}"
echo "🔍 Running code quality checks for YAZE..."
# Check if required tools are available
command -v clang-format >/dev/null 2>&1 || { echo "❌ clang-format not found. Please install it."; exit 1; }
command -v cppcheck >/dev/null 2>&1 || { echo "❌ cppcheck not found. Please install it."; exit 1; }
# Create .clang-format config if it doesn't exist
if [ ! -f .clang-format ]; then
echo "📝 Creating .clang-format configuration..."
clang-format --style=Google --dump-config > .clang-format
fi
echo "✅ Code formatting check..."
# Check formatting without modifying files
FORMATTING_ISSUES=$(find src test -name "*.cc" -o -name "*.h" | head -50 | xargs clang-format --dry-run --Werror --style=Google 2>&1 || true)
if [ -n "$FORMATTING_ISSUES" ]; then
echo "⚠️ Formatting issues found. Run 'make format' to fix them."
echo "$FORMATTING_ISSUES" | head -20
else
echo "✅ All files are properly formatted"
fi
echo "🔍 Running static analysis..."
# Run cppcheck on main source directories
cppcheck --enable=all --error-exitcode=0 \
--suppress=missingIncludeSystem \
--suppress=unusedFunction \
--suppress=unmatchedSuppression \
--suppress=unreadVariable \
--suppress=cstyleCast \
--suppress=variableScope \
src/ 2>&1 | head -30
echo "✅ Quality checks completed!"
echo ""
echo "💡 To fix formatting issues automatically, run:"
echo " find src test -name '*.cc' -o -name '*.h' | xargs clang-format -i --style=Google"
echo ""
echo "💡 For CI/CD pipeline compatibility, ensure:"
echo " - All formatting issues are resolved"
echo " - absl::Status return values are handled with RETURN_IF_ERROR() or PRINT_IF_ERROR()"
echo " - Use Google C++ style for consistency"

View File

@@ -18,7 +18,7 @@ namespace yaze {
namespace editor { namespace editor {
class EditorManager; class EditorManager;
} }
} } // namespace yaze
#if defined(YAZE_ENABLE_IMGUI_TEST_ENGINE) && YAZE_ENABLE_IMGUI_TEST_ENGINE #if defined(YAZE_ENABLE_IMGUI_TEST_ENGINE) && YAZE_ENABLE_IMGUI_TEST_ENGINE
#include "imgui_test_engine/imgui_te_engine.h" #include "imgui_test_engine/imgui_te_engine.h"
@@ -167,36 +167,43 @@ class TestManager {
void DrawTestDashboard(bool* show_dashboard = nullptr); void DrawTestDashboard(bool* show_dashboard = nullptr);
// ROM-dependent testing // ROM-dependent testing
void SetCurrentRom(Rom* rom) { void SetCurrentRom(Rom* rom) {
util::logf("TestManager::SetCurrentRom called with ROM: %p", (void*)rom); util::logf("TestManager::SetCurrentRom called with ROM: %p", (void*)rom);
if (rom) { if (rom) {
util::logf("ROM title: '%s', loaded: %s", rom->title().c_str(), rom->is_loaded() ? "true" : "false"); util::logf("ROM title: '%s', loaded: %s", rom->title().c_str(),
rom->is_loaded() ? "true" : "false");
} }
current_rom_ = rom; current_rom_ = rom;
} }
Rom* GetCurrentRom() const { return current_rom_; } Rom* GetCurrentRom() const { return current_rom_; }
void RefreshCurrentRom(); // Refresh ROM pointer from editor manager void RefreshCurrentRom(); // Refresh ROM pointer from editor manager
// Remove EditorManager dependency to avoid circular includes // Remove EditorManager dependency to avoid circular includes
// Enhanced ROM testing // Enhanced ROM testing
absl::Status LoadRomForTesting(const std::string& filename); absl::Status LoadRomForTesting(const std::string& filename);
void ShowRomComparisonResults(const Rom& before, const Rom& after); void ShowRomComparisonResults(const Rom& before, const Rom& after);
// Test ROM management // Test ROM management
absl::Status CreateTestRomCopy(Rom* source_rom, std::unique_ptr<Rom>& test_rom); absl::Status CreateTestRomCopy(Rom* source_rom,
std::unique_ptr<Rom>& test_rom);
std::string GenerateTestRomFilename(const std::string& base_name); std::string GenerateTestRomFilename(const std::string& base_name);
void OfferTestSessionCreation(const std::string& test_rom_path); void OfferTestSessionCreation(const std::string& test_rom_path);
public: public:
// ROM testing methods (work on copies, not originals) // ROM testing methods (work on copies, not originals)
absl::Status TestRomSaveLoad(Rom* rom); absl::Status TestRomSaveLoad(Rom* rom);
absl::Status TestRomDataIntegrity(Rom* rom); absl::Status TestRomDataIntegrity(Rom* rom);
absl::Status TestRomWithCopy(Rom* source_rom, std::function<absl::Status(Rom*)> test_function); absl::Status TestRomWithCopy(Rom* source_rom,
std::function<absl::Status(Rom*)> test_function);
// Test configuration management // Test configuration management
void DisableTest(const std::string& test_name) { disabled_tests_[test_name] = true; } void DisableTest(const std::string& test_name) {
void EnableTest(const std::string& test_name) { disabled_tests_[test_name] = false; } disabled_tests_[test_name] = true;
bool IsTestEnabled(const std::string& test_name) const { }
void EnableTest(const std::string& test_name) {
disabled_tests_[test_name] = false;
}
bool IsTestEnabled(const std::string& test_name) const {
auto it = disabled_tests_.find(test_name); auto it = disabled_tests_.find(test_name);
return it == disabled_tests_.end() || !it->second; return it == disabled_tests_.end() || !it->second;
} }
@@ -245,7 +252,7 @@ class TestManager {
// ROM-dependent testing // ROM-dependent testing
Rom* current_rom_ = nullptr; Rom* current_rom_ = nullptr;
// Removed editor_manager_ to avoid circular dependency // Removed editor_manager_ to avoid circular dependency
// UI state // UI state
bool show_google_tests_ = false; bool show_google_tests_ = false;
bool show_rom_test_results_ = false; bool show_rom_test_results_ = false;
@@ -253,7 +260,7 @@ class TestManager {
bool show_test_session_dialog_ = false; bool show_test_session_dialog_ = false;
bool show_test_configuration_ = false; bool show_test_configuration_ = false;
std::string test_rom_path_for_session_; std::string test_rom_path_for_session_;
// Test selection and configuration // Test selection and configuration
std::unordered_map<std::string, bool> disabled_tests_; std::unordered_map<std::string, bool> disabled_tests_;
}; };