Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1557,6 +1557,8 @@ Case ID: 123
Template ID: 1
Type ID: 1
Priority ID: 2
AI Generated: No
AI Automated: No
References: JIRA-123, JIRA-456
Created By: 1
Created On: 1646317844
Expand All @@ -1576,6 +1578,8 @@ Case ID: 123
"template_id": 1,
"type_id": 1,
"priority_id": 2,
"is_ai_generated": false,
"is_ai_automated": false,
"refs": "JIRA-123, JIRA-456",
"created_by": 1,
"created_on": 1646317844,
Expand Down Expand Up @@ -1640,6 +1644,8 @@ Found 3 case(s) (showing 1-3):
Suite ID: 2
Priority ID: 2
Type ID: 1
AI Generated: No
AI Automated: No
Labels: automated, regression
Custom Fields: 3 field(s)

Expand All @@ -1649,6 +1655,8 @@ Found 3 case(s) (showing 1-3):
Suite ID: 2
Priority ID: 3
Type ID: 1
AI Generated: Yes
AI Automated: No
Labels: automated
Custom Fields: 2 field(s)

Expand All @@ -1658,6 +1666,8 @@ Found 3 case(s) (showing 1-3):
Suite ID: 2
Priority ID: 2
Type ID: 1
AI Generated: No
AI Automated: No
References: JIRA-789
Custom Fields: 3 field(s)
```
Expand Down
127 changes: 127 additions & 0 deletions tests/test_cmd_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,3 +429,130 @@ def test_list_cases_with_project_name(self, mock_project_client):
mock_client.api_request_handler.case_handler.get_cases.assert_called_once_with(
project_id=99, suite_id=None, priority_id=None, filter_text=None, limit=250, offset=0
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test: get --show-all-fields boolean formatting

The elif isinstance(value, bool) branch in the get() show-all-fields code path (lines 126–127) has no test. test_list_cases_show_all_fields_bool_formatting covers the equivalent branch in list, but the get --show-all-fields branch is completely untested. A test analogous to test_list_cases_show_all_fields_bool_formatting but invoking cmd_cases.get with ["--case-id", "123", "--show-all-fields"] is missing.

@mock.patch("trcli.commands.cmd_cases.ProjectBasedClient")
def test_get_case_displays_ai_fields(self, mock_project_client):
"""Test that get() compact output displays is_ai_generated/is_ai_automated as Yes/No"""
mock_client = self._setup_project_client_mock(mock_project_client)
mock_client.api_request_handler.case_handler.get_case.return_value = (
{
"id": 123,
"title": "Test Case Title",
"section_id": 1,
"suite_id": 2,
"template_id": 1,
"type_id": 1,
"priority_id": 2,
"is_ai_generated": True,
"is_ai_automated": False,
},
"",
)

with patch.object(self.environment, "log") as mock_log, patch.object(
self.environment, "set_parameters"
), patch.object(self.environment, "check_for_required_parameters"):
result = self.runner.invoke(cmd_cases.get, ["--case-id", "123"], obj=self.environment)

assert result.exit_code == 0
log_calls_str = " ".join([str(call) for call in mock_log.call_args_list])
assert "AI Generated: Yes" in log_calls_str
assert "AI Automated: No" in log_calls_str

@mock.patch("trcli.commands.cmd_cases.ProjectBasedClient")
def test_get_case_displays_ai_fields_when_missing(self, mock_project_client):
"""Test that get() compact output defaults AI fields to No when absent from API response"""
mock_client = self._setup_project_client_mock(mock_project_client)
mock_client.api_request_handler.case_handler.get_case.return_value = (
{"id": 123, "title": "Test Case Title", "section_id": 1},
"",
)

with patch.object(self.environment, "log") as mock_log, patch.object(
self.environment, "set_parameters"
), patch.object(self.environment, "check_for_required_parameters"):
result = self.runner.invoke(cmd_cases.get, ["--case-id", "123"], obj=self.environment)

assert result.exit_code == 0
log_calls_str = " ".join([str(call) for call in mock_log.call_args_list])
assert "AI Generated: No" in log_calls_str
assert "AI Automated: No" in log_calls_str

@mock.patch("trcli.commands.cmd_cases.ProjectBasedClient")
def test_list_cases_displays_ai_fields(self, mock_project_client):
"""Test that list() compact output displays is_ai_generated/is_ai_automated per case as Yes/No"""
mock_client = self._setup_project_client_mock(mock_project_client)
mock_client.api_request_handler.case_handler.get_cases.return_value = (
{
"offset": 0,
"limit": 250,
"size": 2,
"cases": [
{
"id": 1,
"title": "Case 1",
"section_id": 1,
"priority_id": 2,
"type_id": 1,
"is_ai_generated": True,
"is_ai_automated": True,
},
{
"id": 2,
"title": "Case 2",
"section_id": 1,
"priority_id": 3,
"type_id": 1,
"is_ai_generated": False,
"is_ai_automated": False,
},
],
},
"",
)

with patch.object(self.environment, "log") as mock_log, patch.object(
self.environment, "set_parameters"
), patch.object(self.environment, "check_for_required_parameters"):
result = self.runner.invoke(cmd_cases.list, [], obj=self.environment)

assert result.exit_code == 0
log_calls_str = " ".join([str(call) for call in mock_log.call_args_list])
assert "AI Generated: Yes" in log_calls_str
assert "AI Automated: Yes" in log_calls_str
assert "AI Generated: No" in log_calls_str
assert "AI Automated: No" in log_calls_str

@mock.patch("trcli.commands.cmd_cases.ProjectBasedClient")
def test_list_cases_show_all_fields_bool_formatting(self, mock_project_client):
"""Test that show-all-fields mode renders boolean fields (e.g. is_ai_generated) as Yes/No, not True/False"""
mock_client = self._setup_project_client_mock(mock_project_client)
mock_client.api_request_handler.case_handler.get_cases.return_value = (
{
"offset": 0,
"limit": 250,
"size": 1,
"cases": [
{
"id": 1,
"title": "Test Case",
"is_ai_generated": True,
"is_ai_automated": False,
}
],
},
"",
)

with patch.object(self.environment, "log") as mock_log, patch.object(
self.environment, "set_parameters"
), patch.object(self.environment, "check_for_required_parameters"):
result = self.runner.invoke(cmd_cases.list, ["--show-all-fields"], obj=self.environment)

assert result.exit_code == 0
log_calls_str = " ".join([str(call) for call in mock_log.call_args_list])
assert "Is Ai Generated: Yes" in log_calls_str
assert "Is Ai Automated: No" in log_calls_str
# Ensure raw Python bool str never leaks into the formatted output
assert "True" not in log_calls_str
assert "False" not in log_calls_str
8 changes: 8 additions & 0 deletions trcli/commands/cmd_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ def get(
environment.log(f" Template ID: {case_data.get('template_id', 'N/A')}")
environment.log(f" Type ID: {case_data.get('type_id', 'N/A')}")
environment.log(f" Priority ID: {case_data.get('priority_id', 'N/A')}")
environment.log(f" AI Generated: {'Yes' if case_data.get('is_ai_generated') else 'No'}")
environment.log(f" AI Automated: {'Yes' if case_data.get('is_ai_automated') else 'No'}")

if case_data.get("milestone_id"):
environment.log(f" Milestone ID: {case_data.get('milestone_id')}")
Expand Down Expand Up @@ -123,6 +125,8 @@ def get(
display_name = key.replace("_", " ").title()
if value is None:
display_value = "N/A"
elif isinstance(value, bool):
display_value = "Yes" if value else "No"
elif isinstance(value, builtins.list):
if value:
display_value = f"{len(value)} item(s): {value}"
Expand Down Expand Up @@ -239,6 +243,8 @@ def list(
# Handle None values
if value is None:
display_value = "N/A"
elif isinstance(value, bool):
display_value = "Yes" if value else "No"
elif isinstance(value, builtins.list):
# Handle list fields (like labels)
if key == "labels" and value:
Expand All @@ -265,6 +271,8 @@ def list(

environment.log(f" Priority ID: {case.get('priority_id', 'N/A')}")
environment.log(f" Type ID: {case.get('type_id', 'N/A')}")
environment.log(f" AI Generated: {'Yes' if case.get('is_ai_generated') else 'No'}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the compact list output, optional fields like refs, labels, and milestone_id are shown conditionally — only when they have a value. But the AI fields are shown unconditionally for every case, even when both are False/absent. If a project never uses AI generation, every case output will have two lines of "No". Is this intentional?

environment.log(f" AI Automated: {'Yes' if case.get('is_ai_automated') else 'No'}")

if case.get("refs"):
refs = case.get("refs", "")
Expand Down
Loading