diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 40743bf..3a7e50e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -180,3 +180,40 @@ jobs: name: "logger-test-results" path: "output/test-results/" retention-days: 7 + + firmware-summary-test: + name: "Firmware Summary Unit Test" + runs-on: "ubuntu-latest" + if: >- + github.event_name == 'push' || github.event_name == 'pull_request' + needs: [] + steps: + - name: "Checkout code" + uses: actions/checkout@v4 + + - name: "Install dependencies" + run: | + sudo apt-get update + sudo apt-get install -y zsh exiftool jq + + - name: "Make test scripts executable" + run: | + chmod +x scripts/testing/*.zsh + + - name: "Setup output directories" + run: | + mkdir -p output/test-results + mkdir -p output/test-temp + + - name: "Run firmware summary unit test" + run: | + echo "๐Ÿงช Running firmware summary unit test..." + ./scripts/testing/run-tests.zsh --firmware-summary + + - name: "Upload firmware summary test results" + if: always() + uses: actions/upload-artifact@v4 + with: + name: "firmware-summary-test-results" + path: "output/test-results/" + retention-days: 7 diff --git a/AI_INSTRUCTIONS.md b/AI_INSTRUCTIONS.md index 6940bc0..8cc16ea 100644 --- a/AI_INSTRUCTIONS.md +++ b/AI_INSTRUCTIONS.md @@ -130,6 +130,73 @@ This document establishes the foundational architectural decisions and design pa - Whenever a new GitHub issue is created, immediately run `scripts/maintenance/generate-issues-markdown.zsh` to update the local Markdown issue list. - After generating the issue list, read the output file (`output/github_issues.md`) to ensure you are memorizing and referencing the latest issues in all future work and communication. +## GitHub Command Intermediate Documents (MANDATORY) +**CRITICAL: For any GitHub issue or PR creation commands with complex formatting or long content, ALWAYS create an intermediate document first to avoid formatting issues and process hangs.** + +**Rationale**: Complex GitHub CLI commands with long bodies, multiple parameters, or special characters can cause formatting issues, syntax errors, or process hangs. Creating intermediate documents ensures reliable command execution and proper formatting. + +**Requirements**: +- **Create intermediate document** for any GitHub command with: + - Long body text (more than 200 characters) + - Multiple parameters or complex formatting + - Special characters or markdown formatting + - Multiple labels or assignees + - Complex issue/PR descriptions + +- **Document location**: `output/` directory +- **Naming convention**: `output/_.md` (e.g., `output/pr_body_20250629_153000.md`) +- **Content format**: Clean markdown with proper formatting + +**Implementation Process**: +1. **Create intermediate document** in `output/` directory +2. **Write content** with proper markdown formatting +3. **Read document content** into variable or use file reference +4. **Execute GitHub command** using the document content +5. **Clean up** intermediate document after successful execution + +**Examples**: +```zsh +# Create intermediate document for complex PR +cat > output/pr_body_$(date +%Y%m%d_%H%M%S).md << 'EOF' +## Summary +Complex PR description with multiple sections... + +## Requirements +- Feature A +- Feature B + +## Motivation +Detailed explanation... + +## Acceptance Criteria +- [ ] Criterion 1 +- [ ] Criterion 2 +EOF + +# Use document in GitHub command +gh pr create --title "title" --body-file output/pr_body_*.md --assignee fxstein --label enhancement +``` + +**Benefits**: +- โœ… **Reliable execution** - Avoids command line length limits +- โœ… **Proper formatting** - Maintains markdown structure +- โœ… **Error prevention** - Reduces syntax and formatting issues +- โœ… **Easy editing** - Can review and modify content before execution +- โœ… **Cleanup** - Intermediate files are in `output/` directory (gitignored) + +**Enforcement**: +- **MANDATORY** for all complex GitHub commands +- **Failure to follow** will result in immediate correction +- **Always use** for issue/PR creation with detailed content +- **Clean up** intermediate files after successful execution + +**Common Use Cases**: +- Creating detailed GitHub issues with multiple sections +- Creating pull requests with comprehensive descriptions +- Adding complex labels and assignees +- Including formatted markdown content +- Multi-line descriptions or requirements + ## Pull Request Issue Closure Rules (MANDATORY) - **NEVER assume whether a PR closes an issue** - always ask the user if the PR closes the entire issue or is just a partial implementation - **Use "Related to #X" instead of "Closes #X"** unless explicitly told by the user that the PR closes the issue diff --git a/docs/release/RELEASE_SUMMARY_INSTRUCTIONS.md b/docs/release/RELEASE_SUMMARY_INSTRUCTIONS.md index fd2aae6..1f0a220 100644 --- a/docs/release/RELEASE_SUMMARY_INSTRUCTIONS.md +++ b/docs/release/RELEASE_SUMMARY_INSTRUCTIONS.md @@ -15,20 +15,46 @@ This document defines the required content and formatting for the major changes - Keep process improvements as a minor part of the summary ## Required Content Sections -- **New GoPro Models**: List any new GoPro camera models added since the base release -- **Official Firmware**: List new official firmware releases added, grouped by model -- **Labs Firmware**: List new GoPro Labs firmware releases added, grouped by model -- **Core Functionality**: SD card management, firmware updates, tool improvements -- **Infrastructure**: CI/CD and process improvements (minor section) + +### 1. Firmware Summary (MANDATORY - Top of Document) +- **MUST** include the current firmware support status at the very top of the release notes +- Run `./scripts/release/generate-firmware-summary.zsh` to generate the firmware table +- This provides users with immediate visibility into supported models and latest firmware versions +- Place this section before any other content + +### 2. New GoPro Models +- List any new GoPro camera models added since the base release + +### 3. Official Firmware +- List new official firmware releases added, grouped by model + +### 4. Labs Firmware +- List new GoPro Labs firmware releases added, grouped by model + +### 5. Core Functionality +- SD card management, firmware updates, tool improvements + +### 6. Infrastructure +- CI/CD and process improvements (minor section) ## Formatting Requirements - **DO NOT** include a main header (e.g., "# Major Changes Since vXX.XX.XX") โ€“ the main process creates this -- Start directly with section headers (e.g., `## New GoPro Models`) +- Start directly with the firmware summary table - Use bullet points for all lists - Group firmware by model and type (Official vs Labs) ## Example Structure ```markdown +## Supported GoPro Models + +The following GoPro camera models are currently supported by GoProX: + +| Model | Latest Official | Latest Labs | +|-------|-----------------|-------------| +| GoPro Max | H19.03.02.02.00 | H19.03.02.02.70 | +| HERO10 Black | H21.01.01.62.00 | H21.01.01.62.70 | +| HERO11 Black | H22.01.02.32.00 | H22.01.02.32.70 | + ## New GoPro Models - HERO12 Black diff --git a/scripts/release/generate-firmware-summary.zsh b/scripts/release/generate-firmware-summary.zsh new file mode 100755 index 0000000..8fe2cbc --- /dev/null +++ b/scripts/release/generate-firmware-summary.zsh @@ -0,0 +1,206 @@ +#!/bin/zsh + +# Generate firmware summary for release notes +# This script creates a comprehensive list of supported GoPro models and their latest firmware versions + +SCRIPT_DIR="${0:A:h}" +source "$SCRIPT_DIR/../core/logger.zsh" +init_logger "generate-firmware-summary" + +log_info "Generating firmware summary for release notes" + +# Function to get latest firmware version for a model +get_latest_firmware() { + local model_dir="$1" + local latest_version="" + + if [[ ! -d "$model_dir" ]]; then + return 1 + fi + + for version_dir in "$model_dir"/*/; do + if [[ -d "$version_dir" ]]; then + local version=$(basename "$version_dir") + if [[ "$version" == ".keep" ]] || [[ "$version" == "README.txt" ]]; then + continue + fi + if [[ "$version" > "$latest_version" ]]; then + latest_version="$version" + fi + fi + done + + echo "$latest_version" +} + +# Initialize associative arrays +typeset -A official_firmware +typeset -A labs_firmware +typeset -a all_models + +# Process official firmware +for model_dir in firmware/official/*/; do + if [[ -d "$model_dir" ]]; then + model_name=$(basename "$model_dir") + model_name=${model_name//\"/} # Remove any embedded quotes + if [[ "$model_name" != ".keep" ]] && [[ "$model_name" != "README.txt" ]]; then + latest_version=$(get_latest_firmware "$model_dir") + official_firmware[$model_name]="$latest_version" + all_models+=("$model_name") + fi + fi +done + +# Process labs firmware +for model_dir in firmware/labs/*/; do + if [[ -d "$model_dir" ]]; then + model_name=$(basename "$model_dir") + model_name=${model_name//\"/} # Remove any embedded quotes + if [[ "$model_name" != ".keep" ]] && [[ "$model_name" != "README.txt" ]]; then + latest_version=$(get_latest_firmware "$model_dir") + labs_firmware[$model_name]="$latest_version" + # Only add to all_models if not already present + if [[ ! " ${all_models[@]} " =~ " ${model_name} " ]]; then + all_models+=("$model_name") + fi + fi + fi +done + +# Sort models with newer models at top +sorted_models=() +custom_order=( + "HERO13 Black" + "HERO (2024)" + "HERO12 Black" + "HERO11 Black" + "HERO11 Black Mini" + "HERO10 Black" + "HERO9 Black" + "HERO8 Black" + "GoPro Max" + "The Remote" +) + +# Function to get highest firmware version for a model +get_highest_firmware() { + local model="$1" + local official_ver="${official_firmware[$model]:-}" + local labs_ver="${labs_firmware[$model]:-}" + + if [[ -n "$official_ver" && -n "$labs_ver" ]]; then + if [[ "$official_ver" > "$labs_ver" ]]; then + echo "$official_ver" + else + echo "$labs_ver" + fi + elif [[ -n "$official_ver" ]]; then + echo "$official_ver" + elif [[ -n "$labs_ver" ]]; then + echo "$labs_ver" + else + echo "" + fi +} + +# Separate known and unknown models +known_models=() +unknown_models=() + +for model in "${all_models[@]}"; do + local found=false + for known_model in "${custom_order[@]}"; do + if [[ "$model" == "$known_model" ]]; then + found=true + break + fi + done + + if [[ "$found" == true ]]; then + known_models+=("$model") + else + unknown_models+=("$model") + fi +done + +# Sort unknown models by firmware version (newest first) and add at the top +if [[ ${#unknown_models[@]} -gt 0 ]]; then + # Create temporary array with model and version pairs + temp_models=() + for model in "${unknown_models[@]}"; do + version=$(get_highest_firmware "$model") + if [[ -n "$version" ]]; then + temp_models+=("$version|$model") + else + temp_models+=("0000.00.00.00.00|$model") + fi + done + + # Sort by version (descending) and extract model names + sorted_unknown=() + while IFS= read -r line; do + if [[ -n "$line" ]]; then + model=$(echo "$line" | cut -d'|' -f2) + sorted_unknown+=("$model") + fi + done < <(printf '%s\n' "${temp_models[@]}" | sort -r) + + # Add unknown models at the top (newest first) + sorted_models+=("${sorted_unknown[@]}") +fi + +# Add known models in the exact custom order specified +for model in "${custom_order[@]}"; do + for known in "${known_models[@]}"; do + if [[ "$model" == "$known" ]]; then + sorted_models+=("$model") + break + fi + done +done + +# Calculate column widths +model_width=5 # "Model" header length +official_width=15 # "Latest Official" header length +labs_width=11 # "Latest Labs" header length + +for model in "${sorted_models[@]}"; do + model_len=${#model} + if [[ $model_len -gt $model_width ]]; then + model_width=$model_len + fi + + official_ver="${official_firmware[$model]:-N/A}" + official_len=${#official_ver} + if [[ $official_len -gt $official_width ]]; then + official_width=$official_len + fi + + labs_ver="${labs_firmware[$model]:-N/A}" + labs_len=${#labs_ver} + if [[ $labs_len -gt $labs_width ]]; then + labs_width=$labs_len + fi +done + +# Generate the summary +log_info "Generating firmware summary markdown" + +cat << 'EOF' +## Supported GoPro Models + +The following GoPro camera models are currently supported by GoProX: + +EOF + +# Generate properly formatted table +printf "| %-${model_width}s | %-${official_width}s | %-${labs_width}s |\n" "Model" "Latest Official" "Latest Labs" +printf "|%s|%s|%s|\n" "$(printf '%*s' $((model_width + 2)) '' | tr ' ' '-')" "$(printf '%*s' $((official_width + 2)) '' | tr ' ' '-')" "$(printf '%*s' $((labs_width + 2)) '' | tr ' ' '-')" + +for model in "${sorted_models[@]}"; do + official_ver="${official_firmware[$model]:-N/A}" + labs_ver="${labs_firmware[$model]:-N/A}" + printf "| %-${model_width}s | %-${official_width}s | %-${labs_width}s |\n" "$model" "$official_ver" "$labs_ver" +done + +log_info "Firmware summary generation completed" \ No newline at end of file diff --git a/scripts/testing/run-tests.zsh b/scripts/testing/run-tests.zsh index f633290..6f8f498 100755 --- a/scripts/testing/run-tests.zsh +++ b/scripts/testing/run-tests.zsh @@ -36,6 +36,7 @@ RUN_MEDIA_TESTS=false RUN_ERROR_TESTS=false RUN_WORKFLOW_TESTS=false RUN_LOGGER_TESTS=false +RUN_FIRMWARE_SUMMARY_TESTS=false VERBOSE=false QUIET=false DEBUG=false @@ -84,6 +85,10 @@ function parse_options() { RUN_LOGGER_TESTS=true shift ;; + --firmware-summary) + RUN_FIRMWARE_SUMMARY_TESTS=true + shift + ;; --verbose|-v) VERBOSE=true shift @@ -113,7 +118,8 @@ function parse_options() { "$RUN_PARAM_TESTS" == false && "$RUN_STORAGE_TESTS" == false && \ "$RUN_INTEGRATION_TESTS" == false && "$RUN_ENHANCED_TESTS" == false && \ "$RUN_MEDIA_TESTS" == false && "$RUN_ERROR_TESTS" == false && \ - "$RUN_WORKFLOW_TESTS" == false && "$RUN_LOGGER_TESTS" == false ]]; then + "$RUN_WORKFLOW_TESTS" == false && "$RUN_LOGGER_TESTS" == false && \ + "$RUN_FIRMWARE_SUMMARY_TESTS" == false ]]; then RUN_ALL_TESTS=true fi @@ -129,6 +135,7 @@ function parse_options() { echo " RUN_ERROR_TESTS=$RUN_ERROR_TESTS" echo " RUN_WORKFLOW_TESTS=$RUN_WORKFLOW_TESTS" echo " RUN_LOGGER_TESTS=$RUN_LOGGER_TESTS" + echo " RUN_FIRMWARE_SUMMARY_TESTS=$RUN_FIRMWARE_SUMMARY_TESTS" fi } @@ -149,6 +156,7 @@ function show_help() { echo " --error Run error handling tests only" echo " --workflow Run workflow tests only" echo " --logger Run logger tests only" + echo " --firmware-summary Run firmware summary tests only" echo " --verbose, -v Enable verbose output" echo " --quiet, -q Suppress output except for failures" echo " --debug Enable debug output" @@ -247,10 +255,14 @@ function run_selected_tests() { test_suite "Integration Workflow Tests" test_integration_workflows_suite fi - if [[ "$RUN_LOGGER_TESTS" == true ]]; then + if [[ "$RUN_ALL_TESTS" == true || "$RUN_LOGGER_TESTS" == true ]]; then test_suite "Logger Tests" test_logger_suite fi + if [[ "$RUN_ALL_TESTS" == true || "$RUN_FIRMWARE_SUMMARY_TESTS" == true ]]; then + test_suite "Firmware Summary Tests" test_firmware_summary_suite + fi + if [[ "$DEBUG" == true ]]; then echo "[DEBUG] Test suite execution complete" echo "[DEBUG] TEST_RESULTS array contents:" diff --git a/scripts/testing/test-suites.zsh b/scripts/testing/test-suites.zsh index 19641dc..c533cfc 100755 --- a/scripts/testing/test-suites.zsh +++ b/scripts/testing/test-suites.zsh @@ -47,6 +47,17 @@ function test_integration_suite() { run_test "integration_error_handling" test_integration_error_handling "Test error handling scenarios" } +# Firmware Summary Tests +function test_firmware_summary_suite() { + run_test "firmware_summary_basic_generation" test_firmware_summary_basic_generation "Test basic firmware summary generation" + run_test "firmware_summary_custom_sorting" test_firmware_summary_custom_sorting "Test custom model sorting order" + run_test "firmware_summary_model_names_with_spaces" test_firmware_summary_model_names_with_spaces "Test handling of model names with spaces" + run_test "firmware_summary_unknown_models" test_firmware_summary_unknown_models "Test handling of unknown models" + run_test "firmware_summary_missing_firmware" test_firmware_summary_missing_firmware "Test handling of models with missing firmware" + run_test "firmware_summary_table_formatting" test_firmware_summary_table_formatting "Test proper markdown table formatting" + run_test "firmware_summary_column_alignment" test_firmware_summary_column_alignment "Test column width calculation and alignment" +} + # Logger Tests function test_logger_suite() { if [[ "$DEBUG" == true ]]; then @@ -394,4 +405,226 @@ function assert_not_contains() { echo " Pattern: '$pattern'" return 1 fi +} + +## Firmware Summary Tests +function test_firmware_summary_basic_generation() { + # Create test firmware structure + create_test_firmware_structure + + # Run the firmware summary script + local output + output=$(./scripts/release/generate-firmware-summary.zsh 2>&1) + local exit_code=$? + + # Test basic functionality + assert_exit_code 0 "$exit_code" "Firmware summary script should exit successfully" + assert_contains "$output" "## Supported GoPro Models" "Output should contain section header" + assert_contains "$output" "Model" "Output should contain table header" + assert_contains "$output" "HERO13 Black" "Output should contain HERO13 Black model" + assert_contains "$output" "HERO \\(2024\\)" "Output should contain HERO (2024) model" + + cleanup_test_firmware_structure +} + +function test_firmware_summary_custom_sorting() { + # Create test firmware structure + create_test_firmware_structure + + # Run the firmware summary script + local output + output=$(./scripts/release/generate-firmware-summary.zsh 2>&1) + + # Test custom sorting order + local hero13_pos=$(echo "$output" | grep -n "HERO13 Black" | cut -d: -f1) + local hero2024_pos=$(echo "$output" | grep -n "HERO (2024)" | cut -d: -f1) + local hero12_pos=$(echo "$output" | grep -n "HERO12 Black" | cut -d: -f1) + local gopro_max_pos=$(echo "$output" | grep -n "GoPro Max" | cut -d: -f1) + + # Verify custom order: HERO13 -> HERO (2024) -> HERO12 -> ... -> GoPro Max + assert_equal true "$(($hero13_pos < $hero2024_pos))" "HERO13 should come before HERO (2024)" + assert_equal true "$(($hero2024_pos < $hero12_pos))" "HERO (2024) should come before HERO12" + assert_equal true "$(($hero12_pos < $gopro_max_pos))" "HERO12 should come before GoPro Max" + + cleanup_test_firmware_structure +} + +function test_firmware_summary_model_names_with_spaces() { + # Create test firmware structure with models that have spaces + create_test_firmware_structure + + # Run the firmware summary script + local output + output=$(./scripts/release/generate-firmware-summary.zsh 2>&1) + + # Test handling of model names with spaces + assert_contains "$output" "HERO \\(2024\\)" "Should handle model name with parentheses and spaces" + assert_contains "$output" "HERO11 Black Mini" "Should handle model name with multiple spaces" + assert_contains "$output" "GoPro Max" "Should handle model name with space" + + cleanup_test_firmware_structure +} + +function test_firmware_summary_unknown_models() { + # Create test firmware structure with unknown models + create_test_firmware_structure_with_unknown_models + + # Run the firmware summary script + local output + output=$(./scripts/release/generate-firmware-summary.zsh 2>&1) + + # Test handling of unknown models + assert_contains "$output" "Unknown Model X" "Should include unknown models" + assert_contains "$output" "Test Camera Y" "Should include other unknown models" + + # Unknown models should appear at the top (sorted by firmware version) + local unknown_x_pos=$(echo "$output" | grep -n "Unknown Model X" | cut -d: -f1) + local hero13_pos=$(echo "$output" | grep -n "HERO13 Black" | cut -d: -f1) + assert_equal true "$(($unknown_x_pos < $hero13_pos))" "Unknown models should appear before known models" + + cleanup_test_firmware_structure_with_unknown_models +} + +function test_firmware_summary_missing_firmware() { + # Create test firmware structure with some models missing firmware + create_test_firmware_structure_with_missing_firmware + + # Run the firmware summary script + local output + output=$(./scripts/release/generate-firmware-summary.zsh 2>&1) + + # Test handling of missing firmware + assert_contains "$output" "N/A" "Should show N/A for missing firmware" + assert_contains "$output" "HERO13 Black" "Should still include models with missing firmware" + + cleanup_test_firmware_structure_with_missing_firmware +} + +function test_firmware_summary_table_formatting() { + # Create test firmware structure + create_test_firmware_structure + + # Run the firmware summary script + local output + output=$(./scripts/release/generate-firmware-summary.zsh 2>&1) + + # Test proper markdown table formatting + assert_contains "$output" "Model" "Should have table header with Model column" + assert_contains "$output" "Latest Official" "Should have table header with Latest Official column" + assert_contains "$output" "Latest Labs" "Should have table header with Latest Labs column" + assert_contains "$output" "---" "Should have table separator line" + assert_contains "$output" "HERO13 Black" "Should have properly formatted table rows" + + cleanup_test_firmware_structure +} + +function test_firmware_summary_column_alignment() { + # Create test firmware structure with varying model name lengths + create_test_firmware_structure_with_varying_lengths + + # Run the firmware summary script + local output + output=$(./scripts/release/generate-firmware-summary.zsh 2>&1) + + # Test column alignment + # Check that all table rows have the same number of pipe characters (3 columns) + local table_rows=$(echo "$output" | grep "^|" | wc -l | tr -d ' ') + local expected_rows=12 # Header + separator + 10 models + assert_equal "$expected_rows" "$table_rows" "Should have correct number of table rows" + + # Check that each row has exactly 3 pipe characters (indicating 3 columns) + local malformed_rows=$(echo "$output" | grep "^|" | grep -v "^|.*|.*|$" | wc -l | tr -d ' ') + assert_equal "0" "$malformed_rows" "All table rows should have exactly 3 columns" + + cleanup_test_firmware_structure_with_varying_lengths +} + +# Helper functions for firmware summary tests +function create_test_firmware_structure() { + # Create official firmware structure + mkdir -p "firmware/official/HERO13 Black/H24.01.02.02.00" + mkdir -p "firmware/official/HERO (2024)/H24.03.02.20.00" + mkdir -p "firmware/official/HERO12 Black/H23.01.02.32.00" + mkdir -p "firmware/official/HERO11 Black/H22.01.02.32.00" + mkdir -p "firmware/official/HERO11 Black Mini/H22.03.02.50.00" + mkdir -p "firmware/official/HERO10 Black/H21.01.01.62.00" + mkdir -p "firmware/official/HERO9 Black/HD9.01.01.72.00" + mkdir -p "firmware/official/HERO8 Black/HD8.01.02.51.00" + mkdir -p "firmware/official/GoPro Max/H19.03.02.02.00" + mkdir -p "firmware/official/The Remote/GP.REMOTE.FW.02.00.01" + + # Create labs firmware structure + mkdir -p "firmware/labs/HERO13 Black/H24.01.02.02.70" + mkdir -p "firmware/labs/HERO12 Black/H23.01.02.32.70" + mkdir -p "firmware/labs/HERO11 Black/H22.01.02.32.70" + mkdir -p "firmware/labs/HERO11 Black Mini/H22.03.02.50.71b" + mkdir -p "firmware/labs/HERO10 Black/H21.01.01.62.70" + mkdir -p "firmware/labs/HERO9 Black/HD9.01.01.72.70" + mkdir -p "firmware/labs/HERO8 Black/HD8.01.02.51.75" + mkdir -p "firmware/labs/GoPro Max/H19.03.02.02.70" +} + +function create_test_firmware_structure_with_unknown_models() { + create_test_firmware_structure + + # Add unknown models with newer firmware versions + mkdir -p "firmware/official/Unknown Model X/Z99.99.99.99.99" + mkdir -p "firmware/official/Test Camera Y/Y88.88.88.88.88" + mkdir -p "firmware/labs/Unknown Model X/Z99.99.99.99.99" + mkdir -p "firmware/labs/Test Camera Y/Y88.88.88.88.88" +} + +function create_test_firmware_structure_with_missing_firmware() { + create_test_firmware_structure + + # Remove some firmware directories to simulate missing firmware + rm -rf "firmware/labs/HERO (2024)" + rm -rf "firmware/labs/The Remote" +} + +function create_test_firmware_structure_with_varying_lengths() { + create_test_firmware_structure + + # Add models with very long names + mkdir -p "firmware/official/Very Long Model Name That Exceeds Normal Length/H99.99.99.99.99" + mkdir -p "firmware/official/Short/H11.11.11.11.11" +} + +function cleanup_test_firmware_structure() { + rm -rf "firmware/official/HERO13 Black" + rm -rf "firmware/official/HERO (2024)" + rm -rf "firmware/official/HERO12 Black" + rm -rf "firmware/official/HERO11 Black" + rm -rf "firmware/official/HERO11 Black Mini" + rm -rf "firmware/official/HERO10 Black" + rm -rf "firmware/official/HERO9 Black" + rm -rf "firmware/official/HERO8 Black" + rm -rf "firmware/official/GoPro Max" + rm -rf "firmware/official/The Remote" + rm -rf "firmware/labs/HERO13 Black" + rm -rf "firmware/labs/HERO12 Black" + rm -rf "firmware/labs/HERO11 Black" + rm -rf "firmware/labs/HERO11 Black Mini" + rm -rf "firmware/labs/HERO10 Black" + rm -rf "firmware/labs/HERO9 Black" + rm -rf "firmware/labs/HERO8 Black" + rm -rf "firmware/labs/GoPro Max" +} + +function cleanup_test_firmware_structure_with_unknown_models() { + cleanup_test_firmware_structure + rm -rf "firmware/official/Unknown Model X" + rm -rf "firmware/official/Test Camera Y" + rm -rf "firmware/labs/Unknown Model X" + rm -rf "firmware/labs/Test Camera Y" +} + +function cleanup_test_firmware_structure_with_missing_firmware() { + cleanup_test_firmware_structure +} + +function cleanup_test_firmware_structure_with_varying_lengths() { + cleanup_test_firmware_structure + rm -rf "firmware/official/Very Long Model Name That Exceeds Normal Length" + rm -rf "firmware/official/Short" } \ No newline at end of file