diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..c99c4a1 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,187 @@ +"""Pytest configuration and fixtures.""" + +import tempfile +from pathlib import Path +import pytest + + +@pytest.fixture +def sample_python_file(tmp_path): + """Create a sample Python file for testing.""" + content = '''"""Sample module for testing stubgen.""" + +def greet(name: str) -> str: + """Greet a person by name. + + Args: + name: The name to greet + + Returns: + The greeting message + """ + return f"Hello, {name}" + + +class Calculator: + """A simple calculator class.""" + + def __init__(self, initial_value: int = 0): + self.value = initial_value + + def add(self, x: int, y: int) -> int: + """Add two numbers.""" + return self.value + x + y + + def multiply(self, x: int, y: int = 2) -> int: + """Multiply numbers.""" + return self.value * x * y + + +def process_list(items: list[str], count: int = 10) -> list[str]: + """Process items from a list. + + Args: + items: List of strings to process + count: Number of items + + Returns: + Processed list + """ + return items[:count] + + +def get_user_info(name: str, age: int = 25, active: bool = True) -> dict: + """Get user information. + + Args: + name: User's name + age: User's age + active: Whether user is active + + Returns: + User info dictionary + """ + return {"name": name, "age": age, "active": active} + + +async def async_fetch(url: str, timeout: int = 30) -> str: + """Fetch data from URL asynchronously. + + Args: + url: URL to fetch + timeout: Request timeout in seconds + + Returns: + Response content + """ + return f"Content from {url}" + + +class DataProcessor: + """Data processing class.""" + + def __init__(self, config: dict): + self.config = config + self.processed = 0 + + def process(self, data: list[dict]) -> list[dict]: + """Process data items. + + Args: + data: List of data dictionaries + + Returns: + Processed data + """ + self.processed = len(data) + return data + + def reset(self): + """Reset processor state.""" + self.processed = 0 +''' + file_path = tmp_path / "sample.py" + file_path.write_text(content) + return file_path + + +@pytest.fixture +def sample_directory(tmp_path): + """Create a directory with multiple Python files.""" + module1 = tmp_path / "module1.py" + module1.write_text('''"""Module 1.""" + +def func1(x: int) -> int: + return x * 2 + +def func2(y: str) -> str: + return y.upper() +''') + + module2 = tmp_path / "module2.py" + module2.write_text('''"""Module 2.""" + +class MyClass: + def method(self, value: float) -> float: + return value / 2 +''') + + subdir = tmp_path / "subpackage" + subdir.mkdir() + subdir_file = subdir / "submodule.py" + subdir_file.write_text('''"""Submodule.""" + +def sub_func() -> bool: + return True +''') + + return tmp_path + + +@pytest.fixture +def untyped_python_file(tmp_path): + """Create a Python file without type annotations.""" + content = '''"""Module without type annotations.""" + +def greet(name): + return f"Hello, {name}" + +def add(a, b): + return a + b + +class Calculator: + def __init__(self, initial=0): + self.value = initial + + def add(self, x, y): + return self.value + x + y +''' + file_path = tmp_path / "untyped.py" + file_path.write_text(content) + return file_path + + +@pytest.fixture +def mixed_file(tmp_path): + """Create a file with mixed typed and untyped code.""" + content = '''"""Mixed typed and untyped code.""" + +def typed_func(x: int, y: str) -> list[str]: + return [str(x), y] + +def untyped_func(a, b): + return a * b + +class MixedClass: + typed_attr: int = 10 + untyped_attr = "hello" + + def typed_method(self, x: int) -> int: + return x * 2 + + def untyped_method(self, x): + return x +''' + file_path = tmp_path / "mixed.py" + file_path.write_text(content) + return file_path