Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mutation test POC #157

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Mutation test POC #157

wants to merge 6 commits into from

Conversation

EmbeddedDevops1
Copy link
Collaborator

@EmbeddedDevops1 EmbeddedDevops1 commented Sep 11, 2024

PR Type

Enhancement, Tests


Description

  • Introduced mutation testing capabilities across multiple components, including CoverAgent, PromptBuilder, and UnitTestGenerator.
  • Added command-line arguments to enable mutation testing and detailed logging.
  • Implemented methods to run mutation tests and log results in UnitTestGenerator.
  • Updated test cases to include mutation testing parameters.
  • Added new test cases for FastAPI application endpoints.
  • Included a new TOML configuration file for mutation test prompts.

Changes walkthrough 📝

Relevant files
Enhancement
CoverAgent.py
Add mutation testing capability to CoverAgent                       

cover_agent/CoverAgent.py

  • Added mutation testing and logging options to the constructor.
  • Integrated mutation testing in the run method.
  • +5/-0     
    PromptBuilder.py
    Support mutation testing in prompt building                           

    cover_agent/PromptBuilder.py

  • Added mutation testing parameter to the constructor.
  • Modified prompt building logic to support mutation testing.
  • +16/-6   
    UnitTestGenerator.py
    Implement mutation testing in UnitTestGenerator                   

    cover_agent/UnitTestGenerator.py

  • Introduced mutation testing and logging options.
  • Implemented run_mutations and run_mutation methods.
  • +116/-1 
    main.py
    Add CLI options for mutation testing                                         

    cover_agent/main.py

    • Added command-line arguments for mutation testing and logging.
    +10/-0   
    Configuration changes
    config_loader.py
    Include mutation test prompt in settings                                 

    cover_agent/settings/config_loader.py

    • Added mutation_test_prompt.toml to settings files.
    +1/-0     
    mutation_test_prompt.toml
    Add mutation test prompt configuration                                     

    cover_agent/settings/mutation_test_prompt.toml

    • Added configuration for mutation testing prompts.
    +85/-0   
    Tests
    test_app.py
    Add test cases for FastAPI application                                     

    templated_tests/python_fastapi/test_app.py

    • Added new test cases for various endpoints.
    +25/-0   
    test_CoverAgent.py
    Update tests for CoverAgent with mutation parameters         

    tests/test_CoverAgent.py

    • Added mutation testing parameters to test cases.
    +6/-2     

    💡 PR-Agent usage:
    Comment /help on the PR to get a list of all available PR-Agent tools and their descriptions

    Copy link
    Contributor

    qodo-merge-pro bot commented Sep 11, 2024

    CI Failure Feedback 🧐

    (Checks updated until commit 3c49340)

    Action: test

    Failed stage: Run tests and generate reports [❌]

    Failure summary:

    The action failed because the required test coverage threshold was not met:

  • The required test coverage was 65%.
  • The actual test coverage achieved was 64.80%.
  • This resulted in the failure of the coverage check.

  • Relevant error logs:
    1:  ##[group]Operating System
    2:  Ubuntu
    ...
    
    712:  plugins: cov-5.0.0, mock-3.14.0, timeout-2.3.1, asyncio-0.23.8, anyio-4.4.0
    713:  asyncio: mode=Mode.STRICT
    714:  collected 72 items
    715:  templated_tests/python_fastapi/test_app.py::test_root 
    716:  -------------------------------- live log call ---------------------------------
    717:  INFO     httpx:_client.py:1026 HTTP Request: GET http://testserver/ "HTTP/1.1 200 OK"
    718:  PASSED                                                                   [  1%]
    719:  tests/test_AICaller.py::TestAICaller::test_call_model_simplified PASSED  [  2%]
    720:  tests/test_AICaller.py::TestAICaller::test_call_model_with_error PASSED  [  4%]
    721:  tests/test_AICaller.py::TestAICaller::test_call_model_error_streaming PASSED [  5%]
    ...
    
    727:  tests/test_CoverAgent.py::TestCoverAgent::test_agent_source_file_not_found PASSED [ 13%]
    728:  tests/test_CoverAgent.py::TestCoverAgent::test_agent_test_file_not_found PASSED [ 15%]
    729:  tests/test_CoverAgent.py::TestCoverAgent::test_duplicate_test_file_with_output_path PASSED [ 16%]
    730:  tests/test_CoverAgent.py::TestCoverAgent::test_duplicate_test_file_without_output_path PASSED [ 18%]
    731:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_parse_coverage_report_cobertura PASSED [ 19%]
    732:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_correct_parsing_for_matching_package_and_class PASSED [ 20%]
    733:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_returns_empty_lists_and_float PASSED [ 22%]
    734:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_parse_coverage_report_unsupported_type PASSED [ 23%]
    735:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_extract_package_and_class_java_file_error PASSED [ 25%]
    736:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_extract_package_and_class_java PASSED [ 26%]
    737:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_verify_report_update_file_not_updated PASSED [ 27%]
    738:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_verify_report_update_file_not_exist PASSED [ 29%]
    739:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_process_coverage_report PASSED [ 30%]
    740:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_parse_missed_covered_lines_jacoco_key_error PASSED [ 31%]
    741:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_parse_coverage_report_lcov_no_coverage_data PASSED [ 33%]
    742:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_parse_coverage_report_lcov_with_coverage_data PASSED [ 34%]
    743:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_parse_coverage_report_lcov_with_multiple_files PASSED [ 36%]
    744:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_parse_coverage_report_lcov_with_feature_flag PASSED [ 37%]
    745:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_parse_coverage_report_cobertura_with_feature_flag PASSED [ 38%]
    746:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_parse_coverage_report_jacoco PASSED [ 40%]
    747:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_parse_coverage_report_cobertura_filename_not_found PASSED [ 41%]
    748:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_parse_coverage_report_lcov_file_read_error PASSED [ 43%]
    749:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_parse_coverage_report_cobertura_all_files PASSED [ 44%]
    750:  tests/test_CoverageProcessor.py::TestCoverageProcessor::test_parse_coverage_report_unsupported_type_with_feature_flag PASSED [ 45%]
    751:  tests/test_FilePreprocessor.py::TestFilePreprocessor::test_c_file PASSED [ 47%]
    752:  tests/test_FilePreprocessor.py::TestFilePreprocessor::test_py_file_with_function_only PASSED [ 48%]
    753:  tests/test_FilePreprocessor.py::TestFilePreprocessor::test_py_file_with_commented_class PASSED [ 50%]
    754:  tests/test_FilePreprocessor.py::TestFilePreprocessor::test_py_file_with_class PASSED [ 51%]
    755:  tests/test_FilePreprocessor.py::TestFilePreprocessor::test_py_file_with_syntax_error PASSED [ 52%]
    756:  tests/test_PromptBuilder.py::TestPromptBuilder::test_initialization_reads_file_contents PASSED [ 54%]
    757:  tests/test_PromptBuilder.py::TestPromptBuilder::test_initialization_handles_file_read_errors PASSED [ 55%]
    758:  tests/test_PromptBuilder.py::TestPromptBuilder::test_empty_included_files_section_not_in_prompt PASSED [ 56%]
    759:  tests/test_PromptBuilder.py::TestPromptBuilder::test_non_empty_included_files_section_in_prompt PASSED [ 58%]
    760:  tests/test_PromptBuilder.py::TestPromptBuilder::test_empty_additional_instructions_section_not_in_prompt PASSED [ 59%]
    761:  tests/test_PromptBuilder.py::TestPromptBuilder::test_empty_failed_test_runs_section_not_in_prompt PASSED [ 61%]
    762:  tests/test_PromptBuilder.py::TestPromptBuilder::test_non_empty_additional_instructions_section_in_prompt PASSED [ 62%]
    763:  tests/test_PromptBuilder.py::TestPromptBuilder::test_non_empty_failed_test_runs_section_in_prompt PASSED [ 63%]
    764:  tests/test_PromptBuilder.py::TestPromptBuilder::test_build_prompt_custom_handles_rendering_exception 
    765:  -------------------------------- live log call ---------------------------------
    766:  ERROR    root:PromptBuilder.py:191 Error rendering prompt: 'NoneType' object has no attribute 'system'
    767:  PASSED                                                                   [ 65%]
    768:  tests/test_PromptBuilder.py::TestPromptBuilder::test_build_prompt_handles_rendering_exception 
    769:  -------------------------------- live log call ---------------------------------
    770:  ERROR    root:PromptBuilder.py:161 Error rendering prompt: Rendering error
    771:  PASSED                                                                   [ 66%]
    772:  tests/test_ReportGenerator.py::TestReportGeneration::test_generate_report PASSED [ 68%]
    773:  tests/test_Runner.py::TestRunner::test_run_command_success PASSED        [ 69%]
    774:  tests/test_Runner.py::TestRunner::test_run_command_with_cwd PASSED       [ 70%]
    775:  tests/test_Runner.py::TestRunner::test_run_command_failure PASSED        [ 72%]
    776:  tests/test_UnitTestDB.py::TestUnitTestDB::test_insert_attempt PASSED     [ 73%]
    777:  tests/test_UnitTestDB.py::TestUnitTestDB::test_dump_to_report PASSED     [ 75%]
    778:  tests/test_UnitTestGenerator.py::TestUnitTestGenerator::test_get_included_files_mixed_paths PASSED [ 76%]
    779:  tests/test_UnitTestGenerator.py::TestUnitTestGenerator::test_get_included_files_valid_paths PASSED [ 77%]
    780:  tests/test_UnitTestGenerator.py::TestExtractErrorMessage::test_extract_single_match PASSED [ 79%]
    781:  tests/test_UnitTestGenerator.py::TestExtractErrorMessage::test_extract_bad_match 
    782:  -------------------------------- live log call ---------------------------------
    783:  ERROR    root:UnitTestGenerator.py:908 Error extracting error message: expected string or bytes-like object, got 'int'
    784:  PASSED                                                                   [ 80%]
    785:  tests/test_load_yaml.py::TestLoadYaml::test_load_valid_yaml PASSED       [ 81%]
    786:  tests/test_load_yaml.py::TestLoadYaml::test_load_invalid_yaml1 
    787:  -------------------------------- live log call ---------------------------------
    788:  INFO     root:utils.py:29 Failed to parse AI prediction: mapping values are not allowed here
    789:  in "<unicode string>", line 12, column 37:
    790:  relevant line: user="""PR Info: aaa
    791:  ^. Attempting to fix YAML formatting.
    792:  INFO     root:utils.py:75 Successfully parsed AI prediction after adding |-
    793:  PASSED                                                                   [ 83%]
    794:  tests/test_load_yaml.py::TestLoadYaml::test_load_invalid_yaml2 
    795:  -------------------------------- live log call ---------------------------------
    796:  INFO     root:utils.py:29 Failed to parse AI prediction: mapping values are not allowed here
    ...
    
    808:  INFO     root:utils.py:112 Successfully parsed AI prediction after removing 1 lines
    809:  PASSED                                                                   [ 87%]
    810:  tests/test_load_yaml.py::test_try_fix_yaml_llama3_8b 
    811:  -------------------------------- live log call ---------------------------------
    812:  INFO     root:utils.py:112 Successfully parsed AI prediction after removing 2 lines
    813:  PASSED                                                                   [ 88%]
    814:  tests/test_load_yaml.py::test_invalid_yaml_wont_parse 
    815:  -------------------------------- live log call ---------------------------------
    816:  INFO     root:utils.py:29 Failed to parse AI prediction: mapping values are not allowed here
    817:  in "<unicode string>", line 3, column 9:
    818:  language: python
    819:  ^. Attempting to fix YAML formatting.
    820:  INFO     root:utils.py:34 Failed to parse AI prediction after fixing YAML formatting.
    ...
    
    823:  tests/test_main.py::TestMain::test_main_source_file_not_found PASSED     [ 93%]
    824:  tests/test_main.py::TestMain::test_main_test_file_not_found PASSED       [ 94%]
    825:  tests/test_version.py::TestGetVersion::test_get_version_happy_path PASSED [ 95%]
    826:  tests/test_version.py::TestGetVersion::test_get_version_file_missing PASSED [ 97%]
    827:  tests/test_version.py::TestGetVersion::test_get_version_empty_or_whitespace_file PASSED [ 98%]
    828:  tests/test_version.py::TestGetVersion::test_get_version_frozen_application PASSED [100%]
    829:  =============================== warnings summary ===============================
    830:  ../../../.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/pydantic/_internal/_config.py:291: 25 warnings
    831:  /home/runner/.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/pydantic/_internal/_config.py:291: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.8/migration/
    832:  warnings.warn(DEPRECATION_MESSAGE, DeprecationWarning)
    833:  ../../../.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:260
    834:  /home/runner/.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:260: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.8/migration/
    835:  @root_validator(pre=True)
    836:  ../../../.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:347
    837:  /home/runner/.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:347: PydanticDeprecatedSince20: `pydantic.config.Extra` is deprecated, use literal values instead (e.g. `extra='allow'`). Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.8/migration/
    838:  extra = Extra.allow  # Allow extra fields
    839:  ../../../.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:350
    840:  /home/runner/.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:350: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.8/migration/
    841:  @root_validator(pre=True)
    842:  ../../../.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:379
    843:  /home/runner/.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:379: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.8/migration/
    844:  @root_validator(pre=True)
    845:  ../../../.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:426
    846:  /home/runner/.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:426: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.8/migration/
    847:  @root_validator(pre=True)
    848:  ../../../.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:495
    849:  /home/runner/.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:495: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.8/migration/
    850:  @root_validator(pre=True)
    851:  ../../../.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:515
    852:  /home/runner/.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:515: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.8/migration/
    853:  @root_validator(pre=True)
    854:  ../../../.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:528
    855:  /home/runner/.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:528: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.8/migration/
    856:  @root_validator(pre=True)
    857:  ../../../.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:573
    858:  /home/runner/.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:573: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.8/migration/
    859:  @root_validator(pre=True)
    860:  ../../../.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:610
    861:  /home/runner/.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:610: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.8/migration/
    862:  @root_validator(pre=True)
    863:  ../../../.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:928
    864:  /home/runner/.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:928: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.8/migration/
    865:  @root_validator(pre=True)
    866:  ../../../.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:955
    867:  /home/runner/.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:955: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.8/migration/
    868:  @root_validator(pre=True)
    869:  ../../../.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:976
    870:  /home/runner/.cache/pypoetry/virtualenvs/cover-agent-a0pACUfe-py3.12/lib/python3.12/site-packages/litellm/proxy/_types.py:976: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.8/migration/
    ...
    
    898:  cover_agent/settings/config_loader.py      20      1    95%
    899:  cover_agent/utils.py                       71      9    87%
    900:  cover_agent/version.py                     11      0   100%
    901:  -----------------------------------------------------------
    902:  TOTAL                                     912    321    65%
    903:  Coverage XML written to file cobertura.xml
    904:  FAIL Required test coverage of 65% not reached. Total coverage: 64.80%
    905:  ======================= 72 passed, 41 warnings in 6.45s ========================
    906:  make: *** [Makefile:8: test] Error 1
    907:  ##[error]Process completed with exit code 2.
    

    ✨ CI feedback usage guide:

    The CI feedback tool (/checks) automatically triggers when a PR has a failed check.
    The tool analyzes the failed checks and provides several feedbacks:

    • Failed stage
    • Failed test name
    • Failure summary
    • Relevant error logs

    In addition to being automatically triggered, the tool can also be invoked manually by commenting on a PR:

    /checks "https://github.com/{repo_name}/actions/runs/{run_number}/job/{job_number}"
    

    where {repo_name} is the name of the repository, {run_number} is the run number of the failed check, and {job_number} is the job number of the failed check.

    Configuration options

    • enable_auto_checks_feedback - if set to true, the tool will automatically provide feedback when a check is failed. Default is true.
    • excluded_checks_list - a list of checks to exclude from the feedback, for example: ["check1", "check2"]. Default is an empty list.
    • enable_help_text - if set to true, the tool will provide a help message with the feedback. Default is true.
    • persistent_comment - if set to true, the tool will overwrite a previous checks comment with the new feedback. Default is true.
    • final_update_message - if persistent_comment is true and updating a previous checks message, the tool will also create a new message: "Persistent checks updated to latest commit". Default is true.

    See more information about the checks tool in the docs.

    Copy link
    Contributor

    PR Reviewer Guide 🔍

    ⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
    🧪 No relevant tests
    🔒 No security concerns identified
    ⚡ Key issues to review

    Potential Bug
    The run_mutation method modifies the source file directly, which could lead to unintended side effects if an exception occurs during test execution.

    Performance Concern
    The run_mutations method creates a new PromptBuilder instance for each mutation, which could be inefficient for large numbers of mutations.

    Code Duplication
    The run_mutation method uses subprocess.run to execute tests, which duplicates functionality already present in the Runner class.

    Copy link
    Contributor

    qodo-merge-pro bot commented Sep 11, 2024

    PR Code Suggestions ✨

    CategorySuggestion                                                                                                                                    Score
    Security
    Use a more secure approach for subprocess execution

    Instead of using subprocess.run() with shlex.split(), consider using the shell=False
    option with a list of arguments. This approach is more secure and avoids potential
    shell injection vulnerabilities.

    cover_agent/UnitTestGenerator.py [817-823]

     result = subprocess.run(
    -    split(self.test_command),
    +    self.test_command.split(),
         text=True,
         capture_output=True,
         cwd=self.test_command_dir,
         timeout=30,
    +    shell=False,
     )
     
    • Apply this suggestion
    Suggestion importance[1-10]: 9

    Why: This suggestion improves security by avoiding potential shell injection vulnerabilities, which is crucial when executing subprocesses.

    9
    Best practice
    Use a temporary file for mutation testing to ensure safety

    Consider using a temporary file to write the mutated code instead of modifying the
    original source file. This approach is safer and prevents potential issues if the
    process is interrupted.

    cover_agent/UnitTestGenerator.py [803-806]

    -# Write the modified content back to the file
    -with open(self.source_file_path, "w") as source_file:
    -    source_file.writelines(modified_content)
    -    source_file.flush()
    +import tempfile
    +import shutil
     
    +# Create a temporary file with the mutated content
    +with tempfile.NamedTemporaryFile(mode='w', delete=False) as temp_file:
    +    temp_file.writelines(modified_content)
    +    temp_file_path = temp_file.name
    +
    +try:
    +    # Use the temporary file for testing
    +    # ... (run the test using temp_file_path instead of self.source_file_path)
    +finally:
    +    # Restore the original content
    +    shutil.copy2(self.source_file_path, temp_file_path)
    +
    • Apply this suggestion
    Suggestion importance[1-10]: 8

    Why: Using a temporary file prevents potential issues with data integrity if the process is interrupted, enhancing the reliability of the mutation testing process.

    8
    ✅ Use context manager for file operations and remove unnecessary flush
    Suggestion Impact:The suggestion to use a context manager for file operations was implemented. The code now uses a 'with' statement to open the file, ensuring it is properly closed after operations.

    code diff:

             with open(self.source_file_path, "r") as source_file:
                 original_content = source_file.readlines()
     

    Consider using a context manager (with statement) to handle file operations. This
    ensures that the file is properly closed after writing, even if an exception occurs.

    cover_agent/UnitTestGenerator.py [804-806]

     with open(self.source_file_path, "w") as source_file:
         source_file.writelines(modified_content)
    -    source_file.flush()
     
    • Apply this suggestion
    Suggestion importance[1-10]: 7

    Why: The suggestion to use a context manager is valid as it ensures proper file handling, and removing the unnecessary flush call simplifies the code without affecting functionality.

    7
    Error handling
    Handle specific exceptions for more precise error handling

    Consider handling specific exceptions instead of using a broad except clause. This
    allows for more precise error handling and helps identify the root cause of issues
    more easily.

    cover_agent/UnitTestGenerator.py [824-826]

    +except subprocess.TimeoutExpired:
    +    logging.error("Test command timed out")
    +    result = None
    +except subprocess.CalledProcessError as e:
    +    logging.error(f"Test command failed with exit code {e.returncode}: {e}")
    +    result = None
     except Exception as e:
    -    logging.error(f"Error running test command: {e}")
    +    logging.error(f"Unexpected error running test command: {e}")
         result = None
     
    • Apply this suggestion
    Suggestion importance[1-10]: 8

    Why: Handling specific exceptions provides better error diagnostics and control, which is beneficial for maintaining robust and understandable code.

    8

    @EmbeddedDevops1 EmbeddedDevops1 self-assigned this Sep 15, 2024
    Updated log and LLM call.
    @EmbeddedDevops1
    Copy link
    Collaborator Author

    /describe

    Copy link
    Contributor

    PR Description updated to latest commit (f0e6d87)

    @EmbeddedDevops1
    Copy link
    Collaborator Author

    /ask This Pull Request adds a new feature called mutation testing. I need to add a markdown file under the docs/ directory that provides the following:

    • Overview of what mutation testing is and how it works
    • How does it run in Cover Agent (hint: it happens after generating and validating the tests in the UnitTestGenerator Class)
    • How to run mutation testing in Cover Agent (hint: See the added args in main.py

    Feel free to propose any other sections that you feel is pertinent that I may have overlooked (based on this PR)

    Copy link
    Contributor

    Ask

    This Pull Request adds a new feature called mutation testing. I need to add a markdown file under the docs/ directory that provides the following: * Overview of what mutation testing is and how it works * How does it run in Cover Agent (hint: it happens after generating and validating the tests in the UnitTestGenerator Class) * How to run mutation testing in Cover Agent (hint: See the added args in main.py Feel free to propose any other sections that you feel is pertinent that I may have overlooked (based on this PR)

    Answer:

    To create a markdown file under the docs/ directory that provides an overview of the new mutation testing feature, you can structure it as follows:


    Mutation Testing in Cover Agent

    Overview of Mutation Testing

    Mutation testing is a technique used to evaluate the quality and effectiveness of test suites. It involves making small changes, or "mutations," to the source code and then running the test suite to see if the tests can detect the changes. The goal is to ensure that the tests are robust enough to catch potential bugs introduced by these mutations. If a test fails due to a mutation, it indicates that the test suite is effective in catching errors. Conversely, if a mutation does not cause any test to fail, it suggests that the test suite may need improvement.

    How Mutation Testing Works in Cover Agent

    In the Cover Agent, mutation testing is integrated into the UnitTestGenerator class. After generating and validating the tests, the mutation testing process is initiated if enabled. Here's a brief overview of how it works:

    1. Mutation Prompt Building: The PromptBuilder class constructs a prompt specifically for mutation testing. This prompt guides the AI to generate potential mutations for the source code.

    2. Running Mutations: The run_mutations method in the UnitTestGenerator class executes the mutation tests. It uses the AI to generate a list of mutations, applies each mutation to the source code, and runs the test suite to check if the mutation is detected.

    3. Logging Results: The results of each mutation test are logged, indicating whether the mutation was caught (i.e., caused a test to fail) or survived (i.e., did not cause any test to fail).

    How to Run Mutation Testing in Cover Agent

    To run mutation testing in Cover Agent, you need to use the command-line arguments added in main.py. Here’s how you can enable and execute mutation testing:

    1. Enable Mutation Testing: Use the --mutation-testing flag when running the Cover Agent. This flag activates the mutation testing feature.

    2. Enable Detailed Logging: If you want more detailed logging of the mutation testing process, use the --more-mutation-logging flag. This will provide additional information about the mutations and their effects.

    Example Command

    python cover_agent/main.py --mutation-testing --more-mutation-logging

    This command will run the Cover Agent with mutation testing enabled and provide detailed logs of the mutation process.

    Additional Sections

    Configuration

    Mutation testing prompts are configured using a TOML file named mutation_test_prompt.toml. This file defines the strategies and templates used for generating mutations. You can customize this file to adjust the mutation strategies according to your needs.

    Limitations and Considerations

    • Performance: Mutation testing can be resource-intensive as it involves running the test suite multiple times with different mutations.
    • Mutation Quality: The effectiveness of mutation testing depends on the quality of the mutations generated. Ensure that the mutation strategies are well-defined to produce meaningful insights.

    This markdown file provides a comprehensive overview of mutation testing in the Cover Agent, detailing its purpose, implementation, and usage instructions.

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    None yet
    Development

    Successfully merging this pull request may close these issues.

    1 participant