diff --git a/README.md b/README.md index f625db3..c72c9cd 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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, @@ -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) @@ -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) @@ -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) ``` diff --git a/tests/test_cmd_cases.py b/tests/test_cmd_cases.py index 636a19c..ce379dc 100644 --- a/tests/test_cmd_cases.py +++ b/tests/test_cmd_cases.py @@ -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 ) + + @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 diff --git a/trcli/commands/cmd_cases.py b/trcli/commands/cmd_cases.py index 584860a..4e62686 100644 --- a/trcli/commands/cmd_cases.py +++ b/trcli/commands/cmd_cases.py @@ -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')}") @@ -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}" @@ -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: @@ -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'}") + environment.log(f" AI Automated: {'Yes' if case.get('is_ai_automated') else 'No'}") if case.get("refs"): refs = case.get("refs", "")