@@ -183,3 +183,149 @@ def test_result_reporter_add_with_children(self):
183183
184184if __name__ == '__main__' :
185185 unittest .main ()
186+
187+
188+ class TestConversionReportIntegration (unittest .TestCase ):
189+ """Tests for ConversionReport → ResultReporter integration.
190+
191+ Reference: R05 §3.5 - ConversionReport Integration test group
192+ Reference: R06 §3.5 - add_from_conversion_report interface
193+ Reference: R04 §1.2 - field operation → ConsequenceType mapping
194+ """
195+
196+ def test_add_from_conversion_report_method_exists (self ):
197+ """ResultReporter should have add_from_conversion_report method."""
198+ from hatch .cli .cli_utils import ResultReporter
199+
200+ reporter = ResultReporter ("test" )
201+ self .assertTrue (hasattr (reporter , 'add_from_conversion_report' ))
202+ self .assertTrue (callable (reporter .add_from_conversion_report ))
203+
204+ def test_updated_maps_to_update_type (self ):
205+ """FieldOperation 'UPDATED' should map to ConsequenceType.UPDATE."""
206+ from hatch .cli .cli_utils import ResultReporter , ConsequenceType
207+ from tests .test_data .fixtures .cli_reporter_fixtures import REPORT_SINGLE_UPDATE
208+
209+ reporter = ResultReporter ("test" )
210+ reporter .add_from_conversion_report (REPORT_SINGLE_UPDATE )
211+
212+ # Should have one resource consequence with one child
213+ self .assertEqual (len (reporter .consequences ), 1 )
214+ self .assertEqual (len (reporter .consequences [0 ].children ), 1 )
215+ self .assertEqual (reporter .consequences [0 ].children [0 ].type , ConsequenceType .UPDATE )
216+
217+ def test_unsupported_maps_to_skip_type (self ):
218+ """FieldOperation 'UNSUPPORTED' should map to ConsequenceType.SKIP."""
219+ from hatch .cli .cli_utils import ResultReporter , ConsequenceType
220+ from tests .test_data .fixtures .cli_reporter_fixtures import REPORT_ALL_UNSUPPORTED
221+
222+ reporter = ResultReporter ("test" )
223+ reporter .add_from_conversion_report (REPORT_ALL_UNSUPPORTED )
224+
225+ # All children should be SKIP type
226+ for child in reporter .consequences [0 ].children :
227+ self .assertEqual (child .type , ConsequenceType .SKIP )
228+
229+ def test_unchanged_maps_to_unchanged_type (self ):
230+ """FieldOperation 'UNCHANGED' should map to ConsequenceType.UNCHANGED."""
231+ from hatch .cli .cli_utils import ResultReporter , ConsequenceType
232+ from tests .test_data .fixtures .cli_reporter_fixtures import REPORT_ALL_UNCHANGED
233+
234+ reporter = ResultReporter ("test" )
235+ reporter .add_from_conversion_report (REPORT_ALL_UNCHANGED )
236+
237+ # All children should be UNCHANGED type
238+ for child in reporter .consequences [0 ].children :
239+ self .assertEqual (child .type , ConsequenceType .UNCHANGED )
240+
241+ def test_field_name_preserved_in_mapping (self ):
242+ """Field name should be preserved in consequence message."""
243+ from hatch .cli .cli_utils import ResultReporter
244+ from tests .test_data .fixtures .cli_reporter_fixtures import REPORT_SINGLE_UPDATE
245+
246+ reporter = ResultReporter ("test" )
247+ reporter .add_from_conversion_report (REPORT_SINGLE_UPDATE )
248+
249+ child_message = reporter .consequences [0 ].children [0 ].message
250+ self .assertIn ("command" , child_message )
251+
252+ def test_old_new_values_preserved (self ):
253+ """Old and new values should be preserved in consequence message."""
254+ from hatch .cli .cli_utils import ResultReporter
255+ from tests .test_data .fixtures .cli_reporter_fixtures import REPORT_MIXED_OPERATIONS
256+
257+ reporter = ResultReporter ("test" )
258+ reporter .add_from_conversion_report (REPORT_MIXED_OPERATIONS )
259+
260+ # Find the command field child (first one with UPDATED)
261+ command_child = reporter .consequences [0 ].children [0 ]
262+ self .assertIn ("node" , command_child .message ) # old value
263+ self .assertIn ("python" , command_child .message ) # new value
264+
265+ def test_all_fields_mapped_no_data_loss (self ):
266+ """All field operations should be mapped (no data loss)."""
267+ from hatch .cli .cli_utils import ResultReporter
268+ from tests .test_data .fixtures .cli_reporter_fixtures import REPORT_MIXED_OPERATIONS
269+
270+ reporter = ResultReporter ("test" )
271+ reporter .add_from_conversion_report (REPORT_MIXED_OPERATIONS )
272+
273+ # REPORT_MIXED_OPERATIONS has 4 field operations
274+ self .assertEqual (len (reporter .consequences [0 ].children ), 4 )
275+
276+ def test_empty_conversion_report_handled (self ):
277+ """Empty ConversionReport should not raise exception."""
278+ from hatch .cli .cli_utils import ResultReporter
279+ from tests .test_data .fixtures .cli_reporter_fixtures import REPORT_EMPTY_FIELDS
280+
281+ reporter = ResultReporter ("test" )
282+ # Should not raise
283+ reporter .add_from_conversion_report (REPORT_EMPTY_FIELDS )
284+
285+ # Should have resource consequence with no children
286+ self .assertEqual (len (reporter .consequences ), 1 )
287+ self .assertEqual (len (reporter .consequences [0 ].children ), 0 )
288+
289+ def test_resource_consequence_type_from_operation (self ):
290+ """Resource consequence type should be derived from report.operation."""
291+ from hatch .cli .cli_utils import ResultReporter , ConsequenceType
292+ from tests .test_data .fixtures .cli_reporter_fixtures import (
293+ REPORT_SINGLE_UPDATE , # operation="create"
294+ REPORT_MIXED_OPERATIONS , # operation="update"
295+ )
296+
297+ reporter1 = ResultReporter ("test" )
298+ reporter1 .add_from_conversion_report (REPORT_SINGLE_UPDATE )
299+ # "create" operation should map to CONFIGURE (for MCP server creation)
300+ self .assertIn (
301+ reporter1 .consequences [0 ].type ,
302+ [ConsequenceType .CONFIGURE , ConsequenceType .CREATE ]
303+ )
304+
305+ reporter2 = ResultReporter ("test" )
306+ reporter2 .add_from_conversion_report (REPORT_MIXED_OPERATIONS )
307+ # "update" operation should map to CONFIGURE or UPDATE
308+ self .assertIn (
309+ reporter2 .consequences [0 ].type ,
310+ [ConsequenceType .CONFIGURE , ConsequenceType .UPDATE ]
311+ )
312+
313+ def test_server_name_in_resource_message (self ):
314+ """Server name should appear in resource consequence message."""
315+ from hatch .cli .cli_utils import ResultReporter
316+ from tests .test_data .fixtures .cli_reporter_fixtures import REPORT_MIXED_OPERATIONS
317+
318+ reporter = ResultReporter ("test" )
319+ reporter .add_from_conversion_report (REPORT_MIXED_OPERATIONS )
320+
321+ self .assertIn ("weather-server" , reporter .consequences [0 ].message )
322+
323+ def test_target_host_in_resource_message (self ):
324+ """Target host should appear in resource consequence message."""
325+ from hatch .cli .cli_utils import ResultReporter
326+ from tests .test_data .fixtures .cli_reporter_fixtures import REPORT_MIXED_OPERATIONS
327+
328+ reporter = ResultReporter ("test" )
329+ reporter .add_from_conversion_report (REPORT_MIXED_OPERATIONS )
330+
331+ self .assertIn ("cursor" , reporter .consequences [0 ].message .lower ())
0 commit comments