# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. from __future__ import annotations import json from pathlib import Path from typing import Any def assert_file_exists(path: Path, description: str = "") -> None: """ Assert that a file exists with a descriptive error message. Args: path: Path to the file that should exist description: Optional description for better error messages """ desc_msg = f" ({description})" if description else "" assert path.exists(), f"Expected file {path}{desc_msg} to exist, but it doesn't" assert path.is_file(), f"Expected {path}{desc_msg} to be a file, but it's not" def assert_directory_exists(path: Path, description: str = "") -> None: """ Assert that a directory exists with a descriptive error message. Args: path: Path to the directory that should exist description: Optional description for better error messages """ desc_msg = f" ({description})" if description else "" assert path.exists(), ( f"Expected directory {path}{desc_msg} to exist, but it doesn't" ) assert path.is_dir(), f"Expected {path}{desc_msg} to be a directory, but it's not" def assert_file_structure(base_path: Path, expected_files: list[str]) -> None: """ Assert that all expected files exist under the base path. Args: base_path: Base directory path expected_files: List of relative file paths that should exist """ for file_path in expected_files: full_path = base_path / file_path assert_file_exists(full_path, "part of expected structure") def assert_directory_structure(base_path: Path, expected_dirs: list[str]) -> None: """ Assert that all expected directories exist under the base path. Args: base_path: Base directory path expected_dirs: List of relative directory paths that should exist """ for dir_path in expected_dirs: full_path = base_path / dir_path assert_directory_exists(full_path, "part of expected structure") def get_directory_tree(path: Path, ignore: set[str] | None = None) -> set[str]: """ Get all files and directories under a path as relative string paths. Args: path: Base path to scan ignore: Set of file/directory names to ignore Returns: Set of relative path strings """ ignore = ignore or {".DS_Store", "__pycache__", ".pytest_cache"} tree: set[str] = set() if not path.exists(): return tree for item in path.rglob("*"): if any(ignored in item.parts for ignored in ignore): continue relative = item.relative_to(path) tree.add(str(relative)) return tree def load_json_file(path: Path) -> dict[str, Any]: """ Load and parse a JSON file. Args: path: Path to the JSON file Returns: Parsed JSON content Raises: AssertionError: If file doesn't exist or isn't valid JSON """ assert_file_exists(path, "JSON file") try: content = json.loads(path.read_text()) return content except json.JSONDecodeError as e: raise AssertionError(f"File {path} contains invalid JSON: {e}") def assert_json_content(path: Path, expected_values: dict[str, Any]) -> None: """ Assert that a JSON file contains expected key-value pairs. Args: path: Path to the JSON file expected_values: Dictionary of expected key-value pairs """ content = load_json_file(path) for key, expected_value in expected_values.items(): assert key in content, f"Expected key '{key}' not found in {path}" actual_value = content[key] assert actual_value == expected_value, ( f"Expected {key}='{expected_value}' but got '{actual_value}' in {path}" ) def assert_file_contains(path: Path, text: str) -> None: """ Assert that a file contains specific text. Args: path: Path to the file text: Text that should be present in the file """ assert_file_exists(path, "text file") content = path.read_text() assert text in content, f"Expected text '{text}' not found in {path}" def assert_file_content_matches(path: Path, expected_content: str) -> None: """ Assert that a file's content exactly matches expected content. Args: path: Path to the file expected_content: Expected file content """ assert_file_exists(path, "content file") actual_content = path.read_text() assert actual_content == expected_content, ( f"File content mismatch in {path}\n" f"Expected:\n{expected_content}\n" f"Actual:\n{actual_content}" ) def create_test_extension_structure( base_path: Path, id_: str, include_frontend: bool = True, include_backend: bool = True, ) -> dict[str, Any]: """ Helper to create expected extension structure for testing. Args: base_path: Base path where extension should be created id_: Unique identifier for extension name: Extension name include_frontend: Whether frontend should be included include_backend: Whether backend should be included Returns: Dictionary with expected paths and metadata """ extension_path = base_path / id_ expected_files = ["extension.json"] expected_dirs: list[str] = [] if include_frontend: expected_dirs.append("frontend") expected_files.append("frontend/package.json") if include_backend: expected_dirs.append("backend") expected_files.append("backend/pyproject.toml") expected = { "extension_path": extension_path, "expected_files": expected_files, "expected_dirs": expected_dirs, } return expected