Back to Repositories

Testing PromptBuilder File Handling and Template Generation in cover-agent

This test suite validates the PromptBuilder class functionality in the cover-agent project, focusing on prompt generation and file handling for test analysis. The tests verify initialization, file reading, section handling, and error management.

Test Coverage Overview

The test suite provides comprehensive coverage of the PromptBuilder class functionality.

Key areas tested include:
  • File initialization and content reading
  • Error handling for file operations
  • Section inclusion/exclusion logic
  • Prompt template rendering
  • End-to-end test run analysis

Implementation Analysis

The testing approach uses pytest fixtures and mocking to isolate components and validate behavior.

Implementation patterns include:
  • Fixture-based test setup using monkeypatch
  • Mock objects for file operations
  • Temporary file handling for E2E tests
  • Exception handling verification

Technical Details

Testing tools and configuration:
  • pytest framework with fixtures
  • unittest.mock for mocking file operations
  • tempfile module for temporary file creation
  • monkeypatch for dependency injection
  • Custom assertion patterns for prompt content validation

Best Practices Demonstrated

The test suite demonstrates strong testing practices including isolation of dependencies, comprehensive error handling, and thorough validation.

Notable practices:
  • Systematic test organization
  • Proper test cleanup
  • Edge case coverage
  • Clear test naming conventions
  • Effective use of pytest features

codium-ai/cover-agent

tests/test_PromptBuilder.py

            
import os
import pytest
import tempfile
from unittest.mock import patch, mock_open
from cover_agent.PromptBuilder import PromptBuilder


class TestPromptBuilder:
    @pytest.fixture(autouse=True)
    def setup_method(self, monkeypatch):
        mock_open_obj = mock_open(read_data="dummy content")
        monkeypatch.setattr("builtins.open", mock_open_obj)
        self.mock_open_obj = mock_open_obj

    def test_initialization_reads_file_contents(self):
        builder = PromptBuilder(
            "source_path",
            "test_path",
            "dummy content",
        )
        assert builder.source_file == "dummy content"
        assert builder.test_file == "dummy content"
        assert builder.code_coverage_report == "dummy content"
        assert builder.included_files == ""  # Updated expected value

    def test_initialization_handles_file_read_errors(self, monkeypatch):
        def mock_open_raise(*args, **kwargs):
            raise IOError("File not found")

        monkeypatch.setattr("builtins.open", mock_open_raise)

        builder = PromptBuilder(
            "source_path",
            "test_path",
            "coverage_report",
        )
        assert "Error reading source_path" in builder.source_file
        assert "Error reading test_path" in builder.test_file

    def test_empty_included_files_section_not_in_prompt(self, monkeypatch):
        # Disable the monkeypatch for open within this test
        monkeypatch.undo()
        builder = PromptBuilder(
            source_file_path="source_path",
            test_file_path="test_path",
            code_coverage_report="coverage_report",
            included_files="Included Files Content",
        )
        # Directly read the real file content for the prompt template
        builder.source_file = "Source Content"
        builder.test_file = "Test Content"
        builder.code_coverage_report = "Coverage Report Content"
        builder.included_files = ""

        result = builder.build_prompt()
        assert "## Additional Includes" not in result["user"]

    def test_non_empty_included_files_section_in_prompt(self, monkeypatch):
        # Disable the monkeypatch for open within this test
        monkeypatch.undo()
        builder = PromptBuilder(
            source_file_path="source_path",
            test_file_path="test_path",
            code_coverage_report="coverage_report",
            included_files="Included Files Content",
        )

        builder.source_file = "Source Content"
        builder.test_file = "Test Content"
        builder.code_coverage_report = "Coverage Report Content"

        result = builder.build_prompt()
        assert "## Additional Includes" in result["user"]
        assert "Included Files Content" in result["user"]

    def test_empty_additional_instructions_section_not_in_prompt(self, monkeypatch):
        # Disable the monkeypatch for open within this test
        monkeypatch.undo()
        builder = PromptBuilder(
            source_file_path="source_path",
            test_file_path="test_path",
            code_coverage_report="coverage_report",
            additional_instructions="",
        )
        builder.source_file = "Source Content"
        builder.test_file = "Test Content"
        builder.code_coverage_report = "Coverage Report Content"

        result = builder.build_prompt()
        assert "## Additional Instructions" not in result["user"]

    def test_empty_failed_test_runs_section_not_in_prompt(self, monkeypatch):
        # Disable the monkeypatch for open within this test
        monkeypatch.undo()
        builder = PromptBuilder(
            source_file_path="source_path",
            test_file_path="test_path",
            code_coverage_report="coverage_report",
            failed_test_runs="",
        )
        builder.source_file = "Source Content"
        builder.test_file = "Test Content"
        builder.code_coverage_report = "Coverage Report Content"

        result = builder.build_prompt()
        assert "## Previous Iterations Failed Tests" not in result["user"]

    def test_non_empty_additional_instructions_section_in_prompt(self, monkeypatch):
        # Disable the monkeypatch for open within this test
        monkeypatch.undo()
        builder = PromptBuilder(
            source_file_path="source_path",
            test_file_path="test_path",
            code_coverage_report="coverage_report",
            additional_instructions="Additional Instructions Content",
        )
        builder.source_file = "Source Content"
        builder.test_file = "Test Content"
        builder.code_coverage_report = "Coverage Report Content"

        result = builder.build_prompt()
        assert "## Additional Instructions" in result["user"]
        assert "Additional Instructions Content" in result["user"]

    # we currently disabled the logic to add failed test runs to the prompt
    def test_non_empty_failed_test_runs_section_in_prompt(self, monkeypatch):
        # Disable the monkeypatch for open within this test
        monkeypatch.undo()
        builder = PromptBuilder(
            source_file_path="source_path",
            test_file_path="test_path",
            code_coverage_report="coverage_report",
            failed_test_runs="Failed Test Runs Content",
        )
        # Directly read the real file content for the prompt template
        builder.source_file = "Source Content"
        builder.test_file = "Test Content"
        builder.code_coverage_report = "Coverage Report Content"

        result = builder.build_prompt()
        assert "## Previous Iterations Failed Tests" in result["user"]
        assert "Failed Test Runs Content" in result["user"]

    def test_build_prompt_custom_handles_rendering_exception(self, monkeypatch):
        def mock_render(*args, **kwargs):
            raise Exception("Rendering error")

        monkeypatch.setattr(
            "jinja2.Environment.from_string",
            lambda *args, **kwargs: type("", (), {"render": mock_render})(),
        )

        builder = PromptBuilder(
            source_file_path="source_path",
            test_file_path="test_path",
            code_coverage_report="coverage_report",
        )
        result = builder.build_prompt_custom("custom_file")
        assert result == {"system": "", "user": ""}

    def test_build_prompt_handles_rendering_exception(self, monkeypatch):
        def mock_render(*args, **kwargs):
            raise Exception("Rendering error")

        monkeypatch.setattr(
            "jinja2.Environment.from_string",
            lambda *args, **kwargs: type("", (), {"render": mock_render})(),
        )

        builder = PromptBuilder(
            source_file_path="source_path",
            test_file_path="test_path",
            code_coverage_report="coverage_report",
        )
        result = builder.build_prompt()
        assert result == {"system": "", "user": ""}

class TestPromptBuilderEndToEnd:
    def test_custom_analyze_test_run_failure(self):
        # Create fake source and test files and tmp files and pass in the paths
        source_file = tempfile.NamedTemporaryFile(mode="w", delete=False)
        source_file.write("def foo():
    pass")
        source_file.close()
        test_file = tempfile.NamedTemporaryFile(mode="w", delete=False)
        test_file.write("def test_foo():
    pass")
        test_file.close()
        tmp_file = tempfile.NamedTemporaryFile(mode="w", delete=False)
        tmp_file.write("tmp file content")
        tmp_file.close()

        builder = PromptBuilder(
            source_file_path=source_file.name,
            test_file_path=test_file.name,
            code_coverage_report=tmp_file.name,
        )

        builder.stderr_from_run = "stderr content"
        builder.stdout_from_run = "stdout content"
        builder.processed_test_file = "processed test file content"

        result = builder.build_prompt_custom("analyze_test_run_failure")
        assert "stderr content" in result["user"]
        assert "stdout content" in result["user"]

        # Clean up
        os.remove(source_file.name)
        os.remove(test_file.name)
        os.remove(tmp_file.name)

    def test_build_prompt_custom_missing_settings(self, monkeypatch):
        # Mock get_settings to return None for the file
        def mock_get_settings():
            return type('Settings', (), {'get': lambda x: None})()
        
        monkeypatch.setattr('cover_agent.PromptBuilder.get_settings', mock_get_settings)
        
        builder = PromptBuilder(
            source_file_path="source_path",
            test_file_path="test_path",
            code_coverage_report="coverage_report"
        )
        
        result = builder.build_prompt_custom("nonexistent_file")
        assert result == {"system": "", "user": ""}