2023-07-06 00:21:08 +03:00
# Generated by CodiumAI
2025-05-26 15:49:06 +09:00
import textwrap
from unittest . mock import Mock
2024-07-03 08:47:59 +03:00
from pr_agent . algo . utils import PRReviewHeader , convert_to_markdown_v2
2024-02-05 09:20:36 +02:00
from pr_agent . tools . pr_description import insert_br_after_x_chars
2023-07-11 16:55:09 +03:00
2023-07-06 00:21:08 +03:00
"""
Code Analysis
Objective :
2024-10-30 09:56:03 +09:00
The objective of the ' convert_to_markdown ' function is to convert a dictionary of data into a markdown - formatted text .
The function takes in a dictionary as input and recursively iterates through its keys and values to generate the
2023-07-06 00:21:08 +03:00
markdown text .
Inputs :
- A dictionary of data containing information about a pull request .
Flow :
- Initialize an empty string variable ' markdown_text ' .
- Create a dictionary ' emojis ' containing emojis for each key in the input dictionary .
- Iterate through the input dictionary :
- If the value is empty , continue to the next iteration .
2024-10-30 09:56:03 +09:00
- If the value is a dictionary , recursively call the ' convert_to_markdown ' function with the value as input and
2023-07-06 00:21:08 +03:00
append the returned markdown text to ' markdown_text ' .
- If the value is a list :
- If the key is ' code suggestions ' , add an additional line break to ' markdown_text ' .
- Get the corresponding emoji for the key from the ' emojis ' dictionary . If no emoji is found , use a dash .
- Append the emoji and key to ' markdown_text ' .
- Iterate through the items in the list :
2024-10-30 09:56:03 +09:00
- If the item is a dictionary and the key is ' code suggestions ' , call the ' parse_code_suggestion ' function with
2023-07-06 00:21:08 +03:00
the item as input and append the returned markdown text to ' markdown_text ' .
- If the item is not empty , append it to ' markdown_text ' .
2024-10-30 09:56:03 +09:00
- If the value is not ' n/a ' , get the corresponding emoji for the key from the ' emojis ' dictionary . If no emoji is
2023-07-06 00:21:08 +03:00
found , use a dash . Append the emoji , key , and value to ' markdown_text ' .
- Return ' markdown_text ' .
Outputs :
- A markdown - formatted string containing the information from the input dictionary .
Additional aspects :
- The function uses recursion to handle nested dictionaries .
- The ' parse_code_suggestion ' function is called for items in the ' code suggestions ' list .
- The function uses emojis to add visual cues to the markdown text .
"""
class TestConvertToMarkdown :
# Tests that the function works correctly with a simple dictionary input
def test_simple_dictionary_input ( self ) :
2024-02-08 20:14:25 +02:00
input_data = { ' review ' : {
' estimated_effort_to_review_[1-5] ' : ' 1, because the changes are minimal and straightforward, focusing on a single functionality addition. \n ' ,
2024-12-25 08:18:28 +02:00
' relevant_tests ' : ' No \n ' , ' possible_issues ' : ' No \n ' , ' security_concerns ' : ' No \n ' } }
2025-05-26 15:49:06 +09:00
expected_output = textwrap . dedent ( f """ \
{ PRReviewHeader . REGULAR . value } 🔍
Here are some key observations to aid the review process :
< table >
< tr > < td > ⏱ ️ & nbsp ; < strong > Estimated effort to review < / strong > : 1 🔵 ⚪ ⚪ ⚪ ⚪ < / td > < / tr >
< tr > < td > 🧪 & nbsp ; < strong > No relevant tests < / strong > < / td > < / tr >
< tr > < td > & nbsp ; < strong > Possible issues < / strong > : No
< / td > < / tr >
< tr > < td > 🔒 & nbsp ; < strong > No security concerns identified < / strong > < / td > < / tr >
< / table >
""" )
assert convert_to_markdown_v2 ( input_data ) . strip ( ) == expected_output . strip ( )
def test_simple_dictionary_input_without_gfm_supported ( self ) :
input_data = { ' review ' : {
' estimated_effort_to_review_[1-5] ' : ' 1, because the changes are minimal and straightforward, focusing on a single functionality addition. \n ' ,
' relevant_tests ' : ' No \n ' , ' possible_issues ' : ' No \n ' , ' security_concerns ' : ' No \n ' } }
expected_output = textwrap . dedent ( """ \
## PR Reviewer Guide 🔍
Here are some key observations to aid the review process :
### ⏱️ Estimated effort to review: 1 🔵⚪⚪⚪⚪
2024-02-08 20:14:25 +02:00
2025-05-26 15:49:06 +09:00
### 🧪 No relevant tests
2024-02-08 20:14:25 +02:00
2025-05-26 15:49:06 +09:00
### Possible issues: No
### 🔒 No security concerns identified
""" )
assert convert_to_markdown_v2 ( input_data , gfm_supported = False ) . strip ( ) == expected_output . strip ( )
def test_key_issues_to_review ( self ) :
input_data = { ' review ' : {
' key_issues_to_review ' : [
{
' relevant_file ' : ' src/utils.py ' ,
' issue_header ' : ' Code Smell ' ,
' issue_content ' : ' The function is too long and complex. ' ,
' start_line ' : 30 ,
' end_line ' : 50 ,
}
]
} }
mock_git_provider = Mock ( )
reference_link = ' https://github.com/qodo/pr-agent/pull/1/files#diff-hashvalue-R174 '
mock_git_provider . get_line_link . return_value = reference_link
expected_output = textwrap . dedent ( f """ \
## PR Reviewer Guide 🔍
Here are some key observations to aid the review process :
< table >
< tr > < td > ⚡ & nbsp ; < strong > Recommended focus areas for review < / strong > < br > < br >
< a href = ' {reference_link} ' > < strong > Code Smell < / strong > < / a > < br > The function is too long and complex .
< / td > < / tr >
< / table >
""" )
assert convert_to_markdown_v2 ( input_data , git_provider = mock_git_provider ) . strip ( ) == expected_output . strip ( )
mock_git_provider . get_line_link . assert_called_with ( ' src/utils.py ' , 30 , 50 )
def test_ticket_compliance ( self ) :
input_data = { ' review ' : {
' ticket_compliance_check ' : [
{
' ticket_url ' : ' https://example.com/ticket/123 ' ,
' ticket_requirements ' : ' - Requirement 1 \n - Requirement 2 \n ' ,
' fully_compliant_requirements ' : ' - Requirement 1 \n - Requirement 2 \n ' ,
' not_compliant_requirements ' : ' ' ,
' requires_further_human_verification ' : ' ' ,
}
]
} }
expected_output = textwrap . dedent ( """ \
## PR Reviewer Guide 🔍
Here are some key observations to aid the review process :
< table >
< tr > < td >
* * 🎫 Ticket compliance analysis ✅ * *
* * [ 123 ] ( https : / / example . com / ticket / 123 ) - Fully compliant * *
Compliant requirements :
- Requirement 1
- Requirement 2
< / td > < / tr >
< / table >
""" )
assert convert_to_markdown_v2 ( input_data ) . strip ( ) == expected_output . strip ( )
def test_can_be_split ( self ) :
input_data = { ' review ' : {
' can_be_split ' : [
{
' relevant_files ' : [
' src/file1.py ' ,
' src/file2.py '
] ,
2025-05-26 16:15:16 +09:00
' title ' : ' Refactoring ' ,
} ,
{
' relevant_files ' : [
' src/file3.py '
] ,
' title ' : ' Bug Fix ' ,
2025-05-26 15:49:06 +09:00
}
]
}
}
expected_output = textwrap . dedent ( """ \
## PR Reviewer Guide 🔍
Here are some key observations to aid the review process :
< table >
2025-05-26 16:15:16 +09:00
< tr > < td > 🔀 < strong > Multiple PR themes < / strong > < br > < br >
< details > < summary >
Sub - PR theme : < b > Refactoring < / b > < / summary >
___
Relevant files :
- src / file1 . py
- src / file2 . py
___
< / details >
< details > < summary >
Sub - PR theme : < b > Bug Fix < / b > < / summary >
___
Relevant files :
- src / file3 . py
___
< / details >
2025-05-26 15:49:06 +09:00
< / td > < / tr >
< / table >
""" )
2024-07-03 08:47:59 +03:00
assert convert_to_markdown_v2 ( input_data ) . strip ( ) == expected_output . strip ( )
2023-07-06 00:21:08 +03:00
# Tests that the function works correctly with an empty dictionary input
def test_empty_dictionary_input ( self ) :
input_data = { }
2023-08-22 20:21:52 +03:00
expected_output = ' '
2024-02-08 20:14:25 +02:00
2024-07-03 08:47:59 +03:00
assert convert_to_markdown_v2 ( input_data ) . strip ( ) == expected_output . strip ( )
2024-02-05 09:20:36 +02:00
2024-02-08 20:14:25 +02:00
def test_dictionary_with_empty_dictionaries ( self ) :
2024-12-25 08:18:28 +02:00
input_data = { ' review ' : { } }
2024-02-08 20:14:25 +02:00
expected_output = ' '
2024-07-03 08:47:59 +03:00
assert convert_to_markdown_v2 ( input_data ) . strip ( ) == expected_output . strip ( )
2024-02-05 09:20:36 +02:00
class TestBR :
def test_br1 ( self ) :
2024-02-05 10:12:47 +02:00
file_change_description = ' - Imported `FilePatchInfo` and `EDIT_TYPE` from `pr_agent.algo.types` instead of `pr_agent.git_providers.git_provider`. '
2024-02-05 09:20:36 +02:00
file_change_description_br = insert_br_after_x_chars ( file_change_description )
2024-02-05 10:12:47 +02:00
expected_output = ( ' <li>Imported <code>FilePatchInfo</code> and <code>EDIT_TYPE</code> from '
' <code>pr_agent.algo.types</code> instead <br>of '
' <code>pr_agent.git_providers.git_provider</code>. ' )
2024-02-05 09:20:36 +02:00
assert file_change_description_br == expected_output
# print("-----")
# print(file_change_description_br)
def test_br2 ( self ) :
2024-02-08 20:14:25 +02:00
file_change_description = (
' - Created a - new -class `ColorPaletteResourcesCollection ColorPaletteResourcesCollection '
' ColorPaletteResourcesCollection ColorPaletteResourcesCollection` ' )
2024-02-05 09:20:36 +02:00
file_change_description_br = insert_br_after_x_chars ( file_change_description )
2024-02-05 10:12:47 +02:00
expected_output = ( ' <li>Created a - new -class <code>ColorPaletteResourcesCollection </code><br><code> '
2024-02-05 13:00:57 +02:00
' ColorPaletteResourcesCollection ColorPaletteResourcesCollection '
' </code><br><code>ColorPaletteResourcesCollection</code> ' )
2024-02-05 09:20:36 +02:00
assert file_change_description_br == expected_output
# print("-----")
2024-02-05 10:12:47 +02:00
# print(file_change_description_br)
2024-02-05 13:00:57 +02:00
def test_br3 ( self ) :
file_change_description = ' Created a new class `ColorPaletteResourcesCollection` which extends `AvaloniaDictionary<ThemeVariant, ColorPaletteResources>` and implements aaa '
file_change_description_br = insert_br_after_x_chars ( file_change_description )
assert file_change_description_br == ( ' Created a new class <code>ColorPaletteResourcesCollection</code> which '
' extends <br><code>AvaloniaDictionary<ThemeVariant, ColorPaletteResources> '
' </code> and implements <br>aaa ' )
# print("-----")
# print(file_change_description_br)