mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-04 12:50:38 +08:00
273 lines
11 KiB
Python
273 lines
11 KiB
Python
# Generated by CodiumAI
|
|
import textwrap
|
|
from unittest.mock import Mock
|
|
|
|
from pr_agent.algo.utils import PRReviewHeader, convert_to_markdown_v2
|
|
from pr_agent.tools.pr_description import insert_br_after_x_chars
|
|
|
|
"""
|
|
Code Analysis
|
|
|
|
Objective:
|
|
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
|
|
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.
|
|
- If the value is a dictionary, recursively call the 'convert_to_markdown' function with the value as input and
|
|
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:
|
|
- If the item is a dictionary and the key is 'code suggestions', call the 'parse_code_suggestion' function with
|
|
the item as input and append the returned markdown text to 'markdown_text'.
|
|
- If the item is not empty, append it to 'markdown_text'.
|
|
- If the value is not 'n/a', get the corresponding emoji for the key from the 'emojis' dictionary. If no emoji is
|
|
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):
|
|
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(f"""\
|
|
{PRReviewHeader.REGULAR.value} 🔍
|
|
|
|
Here are some key observations to aid the review process:
|
|
|
|
<table>
|
|
<tr><td>⏱️ <strong>Estimated effort to review</strong>: 1 🔵⚪⚪⚪⚪</td></tr>
|
|
<tr><td>🧪 <strong>No relevant tests</strong></td></tr>
|
|
<tr><td> <strong>Possible issues</strong>: No
|
|
</td></tr>
|
|
<tr><td>🔒 <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 🔵⚪⚪⚪⚪
|
|
|
|
### 🧪 No relevant tests
|
|
|
|
### 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>⚡ <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'
|
|
],
|
|
'title': 'Refactoring',
|
|
},
|
|
{
|
|
'relevant_files': [
|
|
'src/file3.py'
|
|
],
|
|
'title': 'Bug Fix',
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
expected_output = textwrap.dedent("""\
|
|
## PR Reviewer Guide 🔍
|
|
|
|
Here are some key observations to aid the review process:
|
|
|
|
<table>
|
|
<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>
|
|
|
|
</td></tr>
|
|
</table>
|
|
""")
|
|
|
|
assert convert_to_markdown_v2(input_data).strip() == expected_output.strip()
|
|
|
|
# Tests that the function works correctly with an empty dictionary input
|
|
def test_empty_dictionary_input(self):
|
|
input_data = {}
|
|
|
|
expected_output = ''
|
|
|
|
|
|
assert convert_to_markdown_v2(input_data).strip() == expected_output.strip()
|
|
|
|
def test_dictionary_with_empty_dictionaries(self):
|
|
input_data = {'review': {}}
|
|
|
|
expected_output = ''
|
|
|
|
|
|
assert convert_to_markdown_v2(input_data).strip() == expected_output.strip()
|
|
|
|
class TestBR:
|
|
def test_br1(self):
|
|
file_change_description = '- Imported `FilePatchInfo` and `EDIT_TYPE` from `pr_agent.algo.types` instead of `pr_agent.git_providers.git_provider`.'
|
|
file_change_description_br = insert_br_after_x_chars(file_change_description)
|
|
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>.')
|
|
assert file_change_description_br == expected_output
|
|
# print("-----")
|
|
# print(file_change_description_br)
|
|
|
|
def test_br2(self):
|
|
file_change_description = (
|
|
'- Created a - new -class `ColorPaletteResourcesCollection ColorPaletteResourcesCollection '
|
|
'ColorPaletteResourcesCollection ColorPaletteResourcesCollection`')
|
|
file_change_description_br = insert_br_after_x_chars(file_change_description)
|
|
expected_output = ('<li>Created a - new -class <code>ColorPaletteResourcesCollection </code><br><code>'
|
|
'ColorPaletteResourcesCollection ColorPaletteResourcesCollection '
|
|
'</code><br><code>ColorPaletteResourcesCollection</code>')
|
|
assert file_change_description_br == expected_output
|
|
# print("-----")
|
|
# print(file_change_description_br)
|
|
|
|
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)
|