backend-infra-engineer: Release v0.3.0 snapshot

This commit is contained in:
scawful
2025-09-27 00:25:45 -04:00
parent 8ce29e1436
commit e32ac75b9c
346 changed files with 55946 additions and 11764 deletions

369
scripts/agent.sh Executable file
View File

@@ -0,0 +1,369 @@
#!/usr/bin/env bash
set -euo pipefail
# Unified background agent script for YAZE (macOS launchd, Linux systemd)
# Subcommands:
# install [--build-type X] [--use-inotify] [--ubuntu-bootstrap] [--enable-linger]
# uninstall
# run-once # one-shot build & test
# watch # linux: inotify-based watch loop
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
BUILD_DIR_DEFAULT="${PROJECT_ROOT}/build"
BUILD_TYPE_DEFAULT="Debug"
usage() {
cat <<EOF
Usage: $0 <subcommand> [options]
Subcommands:
install Install background agent
--build-type X CMake build type (default: ${BUILD_TYPE_DEFAULT})
--use-inotify Linux: use long-lived inotify watcher
--ubuntu-bootstrap Install Ubuntu deps via apt (sudo)
--enable-linger Enable user lingering (Linux)
uninstall Remove installed background agent
run-once One-shot build and test
env: BUILD_DIR, BUILD_TYPE
watch Linux: inotify-based watch loop
env: BUILD_DIR, BUILD_TYPE, INTERVAL_SECONDS (fallback)
Environment:
BUILD_DIR Build directory (default: ${BUILD_DIR_DEFAULT})
BUILD_TYPE CMake build type (default: ${BUILD_TYPE_DEFAULT})
EOF
}
build_and_test() {
local build_dir="${BUILD_DIR:-${BUILD_DIR_DEFAULT}}"
local build_type="${BUILD_TYPE:-${BUILD_TYPE_DEFAULT}}"
local log_file="${LOG_FILE:-"${build_dir}/yaze_agent.log"}"
mkdir -p "${build_dir}"
{
echo "==== $(date '+%Y-%m-%d %H:%M:%S') | yaze agent run (type=${build_type}) ===="
echo "Project: ${PROJECT_ROOT}"
cmake -S "${PROJECT_ROOT}" -B "${build_dir}" -DCMAKE_BUILD_TYPE="${build_type}"
cmake --build "${build_dir}" --config "${build_type}" -j
if [[ -x "${build_dir}/bin/yaze_test" ]]; then
"${build_dir}/bin/yaze_test"
else
if command -v ctest >/dev/null 2>&1; then
ctest --test-dir "${build_dir}" --output-on-failure
else
echo "ctest not found and test binary missing. Skipping tests." >&2
exit 1
fi
fi
} >>"${log_file}" 2>&1
}
sub_run_once() {
build_and_test
}
sub_watch() {
local build_dir="${BUILD_DIR:-${BUILD_DIR_DEFAULT}}"
local build_type="${BUILD_TYPE:-${BUILD_TYPE_DEFAULT}}"
local interval="${INTERVAL_SECONDS:-5}"
mkdir -p "${build_dir}"
if command -v inotifywait >/dev/null 2>&1; then
echo "[agent] using inotifywait watcher"
while true; do
BUILD_DIR="${build_dir}" BUILD_TYPE="${build_type}" build_and_test || true
inotifywait -r -e modify,create,delete,move \
"${PROJECT_ROOT}/src" \
"${PROJECT_ROOT}/test" \
"${PROJECT_ROOT}/CMakeLists.txt" \
"${PROJECT_ROOT}/src/CMakeLists.txt" >/dev/null 2>&1 || true
done
else
echo "[agent] inotifywait not found; running periodic loop (${interval}s)"
while true; do
BUILD_DIR="${build_dir}" BUILD_TYPE="${build_type}" build_and_test || true
sleep "${interval}"
done
fi
}
ensure_exec() {
if [[ ! -x "$1" ]]; then
chmod +x "$1"
fi
}
ubuntu_bootstrap() {
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y inotify-tools build-essential cmake ninja-build pkg-config \
libsdl2-dev libpng-dev libglew-dev libwavpack-dev libabsl-dev \
libboost-all-dev libboost-python-dev python3-dev libpython3-dev
else
echo "apt-get not found; skipping Ubuntu bootstrap" >&2
fi
}
enable_linger_linux() {
if command -v loginctl >/dev/null 2>&1; then
if sudo -n true 2>/dev/null; then
sudo loginctl enable-linger "$USER" || true
else
echo "Note: enabling linger may require sudo: sudo loginctl enable-linger $USER" >&2
fi
fi
}
# Wrapper to run systemctl --user with a session bus in headless shells
systemctl_user() {
# Only apply on Linux
if [[ "$(uname -s)" != "Linux" ]]; then
systemctl "$@"
return
fi
local uid
uid="$(id -u)"
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/${uid}}"
export DBUS_SESSION_BUS_ADDRESS="${DBUS_SESSION_BUS_ADDRESS:-unix:path=${XDG_RUNTIME_DIR}/bus}"
if [[ ! -S "${XDG_RUNTIME_DIR}/bus" ]]; then
echo "[agent] Warning: user bus not found at ${XDG_RUNTIME_DIR}/bus. If this fails, run: sudo loginctl enable-linger $USER" >&2
fi
systemctl --user "$@"
}
is_systemd_available() {
# True if systemd is PID 1 and systemctl exists and a user bus likely available
if [[ ! -d /run/systemd/system ]]; then
return 1
fi
if ! command -v systemctl >/dev/null 2>&1; then
return 1
fi
return 0
}
start_userland_agent() {
local build_type="${1}"
local build_dir="${2}"
local agent_home="$HOME/.local/share/yaze-agent"
mkdir -p "${agent_home}"
local log_file="${agent_home}/agent.log"
nohup env BUILD_TYPE="${build_type}" BUILD_DIR="${build_dir}" "${SCRIPT_DIR}/agent.sh" watch >>"${log_file}" 2>&1 & echo $! > "${agent_home}/agent.pid"
echo "Userland agent started (PID $(cat "${agent_home}/agent.pid")) - logs: ${log_file}"
}
stop_userland_agent() {
local agent_home="$HOME/.local/share/yaze-agent"
local pid_file="${agent_home}/agent.pid"
if [[ -f "${pid_file}" ]]; then
local pid
pid="$(cat "${pid_file}")"
if kill -0 "${pid}" >/dev/null 2>&1; then
kill "${pid}" || true
fi
rm -f "${pid_file}"
echo "Stopped userland agent"
fi
}
install_macos() {
local build_type="${1}"
local build_dir="${2}"
local label="com.yaze.watchtest"
local plist_path="$HOME/Library/LaunchAgents/${label}.plist"
mkdir -p "${build_dir}"
cat >"$plist_path" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>${label}</string>
<key>RunAtLoad</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/bin/zsh</string>
<string>-lc</string>
<string>"${SCRIPT_DIR}/agent.sh" run-once</string>
</array>
<key>WorkingDirectory</key>
<string>${PROJECT_ROOT}</string>
<key>WatchPaths</key>
<array>
<string>${PROJECT_ROOT}/src</string>
<string>${PROJECT_ROOT}/test</string>
<string>${PROJECT_ROOT}/CMakeLists.txt</string>
<string>${PROJECT_ROOT}/src/CMakeLists.txt</string>
</array>
<key>StandardOutPath</key>
<string>${build_dir}/yaze_agent.out.log</string>
<key>StandardErrorPath</key>
<string>${build_dir}/yaze_agent.err.log</string>
<key>EnvironmentVariables</key>
<dict>
<key>BUILD_TYPE</key><string>${build_type}</string>
<key>BUILD_DIR</key><string>${build_dir}</string>
</dict>
</dict>
</plist>
PLIST
launchctl unload -w "$plist_path" 2>/dev/null || true
launchctl load -w "$plist_path"
echo "LaunchAgent installed and loaded: ${plist_path}"
}
install_linux() {
local build_type="${1}"
local build_dir="${2}"
local use_inotify="${3}"
local systemd_dir="$HOME/.config/systemd/user"
local service_name="yaze-watchtest.service"
local path_name="yaze-watchtest.path"
mkdir -p "${systemd_dir}" "${build_dir}"
if ! is_systemd_available; then
echo "[agent] systemd not available; installing userland background agent"
start_userland_agent "${build_type}" "${build_dir}"
return
fi
if [[ "${use_inotify}" == "1" ]]; then
cat >"${systemd_dir}/yaze-watchtest-inotify.service" <<UNIT
[Unit]
Description=Yaze inotify watcher build-and-test
[Service]
Type=simple
Environment=BUILD_TYPE=${build_type}
Environment=BUILD_DIR=${build_dir}
WorkingDirectory=${PROJECT_ROOT}
ExecStart=/bin/bash -lc '"${SCRIPT_DIR}/agent.sh" watch'
Restart=always
RestartSec=2
[Install]
WantedBy=default.target
UNIT
systemctl_user daemon-reload
systemctl_user enable --now yaze-watchtest-inotify.service
echo "systemd user service enabled: yaze-watchtest-inotify.service"
return
fi
cat >"${systemd_dir}/${service_name}" <<UNIT
[Unit]
Description=Yaze build-and-test (one-shot)
[Service]
Type=oneshot
Environment=BUILD_TYPE=${build_type}
Environment=BUILD_DIR=${build_dir}
WorkingDirectory=${PROJECT_ROOT}
ExecStart=/bin/bash -lc '"${SCRIPT_DIR}/agent.sh" run-once'
UNIT
cat >"${systemd_dir}/${path_name}" <<UNIT
[Unit]
Description=Watch Yaze src/test for changes
[Path]
PathModified=${PROJECT_ROOT}/src
PathModified=${PROJECT_ROOT}/test
PathModified=${PROJECT_ROOT}/CMakeLists.txt
PathModified=${PROJECT_ROOT}/src/CMakeLists.txt
Unit=${service_name}
[Install]
WantedBy=default.target
UNIT
systemctl_user daemon-reload
systemctl_user enable --now "$path_name"
echo "systemd user path unit enabled: ${path_name}"
systemctl_user start "$service_name" || true
}
sub_install() {
local build_type="${BUILD_TYPE:-${BUILD_TYPE_DEFAULT}}"
local build_dir="${BUILD_DIR:-${BUILD_DIR_DEFAULT}}"
local use_inotify=0
local do_bootstrap=0
local do_linger=0
while [[ $# -gt 0 ]]; do
case "$1" in
--build-type) build_type="$2"; shift 2 ;;
--use-inotify) use_inotify=1; shift ;;
--ubuntu-bootstrap) do_bootstrap=1; shift ;;
--enable-linger) do_linger=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown option for install: $1" >&2; usage; exit 1 ;;
esac
done
case "$(uname -s)" in
Darwin)
install_macos "${build_type}" "${build_dir}" ;;
Linux)
if (( do_bootstrap == 1 )); then ubuntu_bootstrap; fi
if (( do_linger == 1 )); then enable_linger_linux; fi
install_linux "${build_type}" "${build_dir}" "${use_inotify}" ;;
*)
echo "Unsupported platform" >&2; exit 1 ;;
esac
}
sub_uninstall() {
case "$(uname -s)" in
Darwin)
local label="com.yaze.watchtest"
local plist_path="$HOME/Library/LaunchAgents/${label}.plist"
launchctl unload -w "$plist_path" 2>/dev/null || true
rm -f "$plist_path"
echo "Removed LaunchAgent ${label}"
;;
Linux)
local systemd_dir="$HOME/.config/systemd/user"
if is_systemd_available; then
systemctl_user stop yaze-watchtest.path 2>/dev/null || true
systemctl_user disable yaze-watchtest.path 2>/dev/null || true
systemctl_user stop yaze-watchtest.service 2>/dev/null || true
systemctl_user stop yaze-watchtest-inotify.service 2>/dev/null || true
systemctl_user disable yaze-watchtest-inotify.service 2>/dev/null || true
rm -f "${systemd_dir}/yaze-watchtest.service" "${systemd_dir}/yaze-watchtest.path" "${systemd_dir}/yaze-watchtest-inotify.service"
systemctl_user daemon-reload || true
echo "Removed systemd user units"
fi
stop_userland_agent
;;
*) echo "Unsupported platform" >&2; exit 1 ;;
esac
}
main() {
ensure_exec "$0"
local subcmd="${1:-}"; shift || true
case "${subcmd}" in
install) sub_install "$@" ;;
uninstall) sub_uninstall ;;
run-once) sub_run_once ;;
watch) sub_watch ;;
-h|--help|help|"") usage ;;
*) echo "Unknown subcommand: ${subcmd}" >&2; usage; exit 1 ;;
esac
}
main "$@"

138
scripts/create_release.sh Executable file
View File

@@ -0,0 +1,138 @@
#!/bin/bash
# Script to create a proper release tag for YAZE
# Usage: ./scripts/create_release.sh [version]
# Example: ./scripts/create_release.sh 0.3.0
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Function to print colored output
print_info() {
echo -e "${BLUE} $1${NC}"
}
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
print_error() {
echo -e "${RED}$1${NC}"
}
# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
print_error "Not in a git repository!"
exit 1
fi
# Check if we're on master branch
current_branch=$(git branch --show-current)
if [ "$current_branch" != "master" ]; then
print_warning "You're on branch '$current_branch', not 'master'"
read -p "Continue anyway? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_info "Switching to master branch..."
git checkout master
fi
fi
# Get version argument or prompt for it
if [ $# -eq 0 ]; then
echo
print_info "Enter the version number (e.g., 0.3.0, 1.0.0-beta, 2.1.0-rc1):"
read -p "Version: " version
else
version=$1
fi
# Validate version format
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-.*)?$ ]]; then
print_error "Invalid version format: '$version'"
print_info "Version must follow semantic versioning (e.g., 1.2.3 or 1.2.3-beta)"
exit 1
fi
# Create tag with v prefix
tag="v$version"
# Check if tag already exists
if git tag -l | grep -q "^$tag$"; then
print_error "Tag '$tag' already exists!"
exit 1
fi
# Show current status
echo
print_info "Current repository status:"
git status --short
# Check for uncommitted changes
if ! git diff-index --quiet HEAD --; then
print_warning "You have uncommitted changes!"
read -p "Continue with creating release? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_info "Please commit your changes first, then run this script again."
exit 1
fi
fi
# Show what will happen
echo
print_info "Creating release for YAZE:"
echo " 📦 Version: $version"
echo " 🏷️ Tag: $tag"
echo " 🌿 Branch: $current_branch"
echo " 📝 Changelog: docs/C1-changelog.md"
echo
# Confirm
read -p "Create this release? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_info "Release creation cancelled."
exit 0
fi
# Create and push tag
print_info "Creating tag '$tag'..."
if git tag -a "$tag" -m "Release $tag"; then
print_success "Tag '$tag' created successfully!"
else
print_error "Failed to create tag!"
exit 1
fi
print_info "Pushing tag to origin..."
if git push origin "$tag"; then
print_success "Tag pushed successfully!"
else
print_error "Failed to push tag!"
print_info "You can manually push with: git push origin $tag"
exit 1
fi
echo
print_success "🎉 Release $tag created successfully!"
print_info "The GitHub Actions release workflow will now:"
echo " • Build packages for Windows, macOS, and Linux"
echo " • Extract changelog from docs/C1-changelog.md"
echo " • Create GitHub release with all assets"
echo " • Include themes, fonts, layouts, and documentation"
echo
print_info "Check the release progress at:"
echo " https://github.com/scawful/yaze/actions"
echo
print_info "The release will be available at:"
echo " https://github.com/scawful/yaze/releases/tag/$tag"

94
scripts/extract_changelog.py Executable file
View File

@@ -0,0 +1,94 @@
#!/usr/bin/env python3
"""
Extract changelog section for a specific version from docs/C1-changelog.md
Usage: python3 extract_changelog.py <version>
Example: python3 extract_changelog.py 0.3.0
"""
import re
import sys
import os
def extract_version_changelog(version_num, changelog_file):
"""Extract changelog section for specific version"""
try:
with open(changelog_file, 'r') as f:
content = f.read()
# Find the section for this version
version_pattern = rf"## {re.escape(version_num)}\s*\([^)]+\)"
next_version_pattern = r"## \d+\.\d+\.\d+\s*\([^)]+\)"
# Find start of current version section
version_match = re.search(version_pattern, content)
if not version_match:
return f"Changelog section not found for version {version_num}."
start_pos = version_match.end()
# Find start of next version section
remaining_content = content[start_pos:]
next_match = re.search(next_version_pattern, remaining_content)
if next_match:
end_pos = start_pos + next_match.start()
section_content = content[start_pos:end_pos].strip()
else:
section_content = remaining_content.strip()
return section_content
except Exception as e:
return f"Error reading changelog: {str(e)}"
def main():
if len(sys.argv) != 2:
print("Usage: python3 extract_changelog.py <version>")
sys.exit(1)
version_num = sys.argv[1]
changelog_file = "docs/C1-changelog.md"
# Check if changelog file exists
if not os.path.exists(changelog_file):
print(f"Error: Changelog file {changelog_file} not found")
sys.exit(1)
# Extract changelog content
changelog_content = extract_version_changelog(version_num, changelog_file)
# Generate full release notes
release_notes = f"""# Yaze v{version_num} Release Notes
{changelog_content}
## Download Instructions
### Windows
- Download `yaze-windows-x64.zip` for 64-bit Windows
- Download `yaze-windows-x86.zip` for 32-bit Windows
- Extract and run `yaze.exe`
### macOS
- Download `yaze-macos.dmg`
- Mount the DMG and drag Yaze to Applications
- You may need to allow the app in System Preferences > Security & Privacy
### Linux
- Download `yaze-linux-x64.tar.gz`
- Extract: `tar -xzf yaze-linux-x64.tar.gz`
- Run: `./yaze`
## System Requirements
- **Windows**: Windows 10 or later (64-bit recommended)
- **macOS**: macOS 10.15 (Catalina) or later
- **Linux**: Ubuntu 20.04 or equivalent, with X11 or Wayland
## Support
For issues and questions, please visit our [GitHub Issues](https://github.com/scawful/yaze/issues) page.
"""
print(release_notes)
if __name__ == "__main__":
main()

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"

150
scripts/test_asar_integration.py Executable file
View File

@@ -0,0 +1,150 @@
#!/usr/bin/env python3
"""
Asar Integration Test Script for Yaze
Tests the Asar 65816 assembler integration with real ROM files
"""
import os
import sys
import subprocess
import shutil
import tempfile
from pathlib import Path
def find_project_root():
"""Find the yaze project root directory"""
current = Path(__file__).parent
while current != current.parent:
if (current / "CMakeLists.txt").exists():
return current
current = current.parent
raise FileNotFoundError("Could not find yaze project root")
def main():
print("🧪 Yaze Asar Integration Test")
print("=" * 50)
project_root = find_project_root()
build_dir = project_root / "build_test"
rom_path = build_dir / "bin" / "zelda3.sfc"
test_patch = project_root / "test" / "assets" / "test_patch.asm"
# Check if ROM file exists
if not rom_path.exists():
print(f"❌ ROM file not found: {rom_path}")
print(" Please ensure you have a test ROM at the expected location")
return 1
print(f"✅ Found ROM file: {rom_path}")
print(f" Size: {rom_path.stat().st_size:,} bytes")
# Check if test patch exists
if not test_patch.exists():
print(f"❌ Test patch not found: {test_patch}")
return 1
print(f"✅ Found test patch: {test_patch}")
# Check if z3ed tool exists
z3ed_path = build_dir / "bin" / "z3ed"
if not z3ed_path.exists():
print(f"❌ z3ed CLI tool not found: {z3ed_path}")
print(" Run: cmake --build build_test --target z3ed")
return 1
print(f"✅ Found z3ed CLI tool: {z3ed_path}")
# Create temporary directory for testing
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
test_rom_path = temp_path / "test_rom.sfc"
patched_rom_path = temp_path / "patched_rom.sfc"
# Copy ROM to temporary location
shutil.copy2(rom_path, test_rom_path)
print(f"📋 Copied ROM to: {test_rom_path}")
# Test 1: Apply patch using z3ed CLI
print("\n🔧 Test 1: Applying patch with z3ed CLI")
try:
cmd = [str(z3ed_path), "asar", str(test_patch), str(test_rom_path)]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if result.returncode == 0:
print("✅ Patch applied successfully!")
if result.stdout:
print(f" Output: {result.stdout.strip()}")
else:
print(f"❌ Patch failed with return code: {result.returncode}")
if result.stderr:
print(f" Error: {result.stderr.strip()}")
return 1
except subprocess.TimeoutExpired:
print("❌ Patch operation timed out")
return 1
except Exception as e:
print(f"❌ Error running patch: {e}")
return 1
# Test 2: Verify ROM was modified
print("\n🔍 Test 2: Verifying ROM modification")
original_size = rom_path.stat().st_size
modified_size = test_rom_path.stat().st_size
print(f" Original ROM size: {original_size:,} bytes")
print(f" Modified ROM size: {modified_size:,} bytes")
# Read first few bytes to check for changes
with open(rom_path, 'rb') as orig_file, open(test_rom_path, 'rb') as mod_file:
orig_bytes = orig_file.read(1024)
mod_bytes = mod_file.read(1024)
if orig_bytes != mod_bytes:
print("✅ ROM was successfully modified!")
# Count different bytes
diff_count = sum(1 for a, b in zip(orig_bytes, mod_bytes) if a != b)
print(f" {diff_count} bytes differ in first 1KB")
else:
print("⚠️ No differences detected in first 1KB")
print(" (Patch may have been applied to a different region)")
# Test 3: Run unit tests if available
yaze_test_path = build_dir / "bin" / "yaze_test"
if yaze_test_path.exists():
print("\n🧪 Test 3: Running Asar unit tests")
try:
# Run only the Asar-related tests
cmd = [str(yaze_test_path), "--gtest_filter=*Asar*", "--gtest_brief=1"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
print(f" Exit code: {result.returncode}")
if result.stdout:
# Extract test results
lines = result.stdout.split('\n')
for line in lines:
if 'PASSED' in line or 'FAILED' in line or 'RUN' in line:
print(f" {line}")
if result.returncode == 0:
print("✅ Unit tests passed!")
else:
print("⚠️ Some unit tests failed (this may be expected)")
except subprocess.TimeoutExpired:
print("❌ Unit tests timed out")
except Exception as e:
print(f"⚠️ Error running unit tests: {e}")
else:
print("\n⚠️ Test 3: yaze_test executable not found")
print("\n🎉 Asar integration test completed!")
print("\nNext steps:")
print("- Run full test suite with: ctest --test-dir build_test")
print("- Test Asar functionality in the main yaze application")
print("- Create custom assembly patches for your ROM hacking projects")
return 0
if __name__ == "__main__":
sys.exit(main())