@@ -294,5 +294,109 @@ def test_no_reject(self):
294294 with self .assertRaises (check50 .Failure ):
295295 self .process .reject ()
296296
297+ class TestMismatch (unittest .TestCase ):
298+ """Test Mismatch exception class for proper JSON serialization."""
299+
300+ def test_json_serialization_with_strings (self ):
301+ """Test that regular strings are properly escaped for JSON."""
302+ import json
303+
304+ test_cases = [
305+ # Regular strings
306+ ("hello" , "world" ),
307+ # Strings with quotes
308+ ('Hello "World"' , 'Goodbye "World"' ),
309+ # Strings with newlines
310+ ("First\n Second" , "First\n Different" ),
311+ # Strings with backslashes
312+ ("Path\\ to\\ file" , "Path\\ to\\ other" ),
313+ # JSON-like strings
314+ ('{"key": "value"}' , '{"key": "different"}' ),
315+ # Mixed special characters
316+ ('Line with \\ and " and \n ' , 'Another \\ line " with \n ' ),
317+ ]
318+
319+ for expected , actual in test_cases :
320+ with self .subTest (expected = expected , actual = actual ):
321+ mismatch = check50 .Mismatch (expected , actual )
322+
323+ # Ensure payload can be serialized to JSON
324+ json_str = json .dumps (mismatch .payload )
325+
326+ # Ensure it can be parsed back
327+ parsed = json .loads (json_str )
328+
329+ # Verify expected fields are present
330+ self .assertIn ('rationale' , parsed )
331+ self .assertIn ('expected' , parsed )
332+ self .assertIn ('actual' , parsed )
333+ self .assertIsNone (parsed .get ('help' ))
334+
335+ def test_json_serialization_with_special_values (self ):
336+ """Test that special values like EOF and class types are handled."""
337+ import json
338+ from pexpect .exceptions import EOF , TIMEOUT
339+
340+ test_cases = [
341+ # EOF and TIMEOUT constants
342+ (check50 .EOF , "some output" ),
343+ ("some input" , check50 .EOF ),
344+ (check50 .EOF , check50 .EOF ),
345+ # Class types (simulating the error case)
346+ (EOF , "output" ),
347+ ("input" , EOF ),
348+ (EOF , TIMEOUT ),
349+ ]
350+
351+ for expected , actual in test_cases :
352+ with self .subTest (expected = expected , actual = actual ):
353+ mismatch = check50 .Mismatch (expected , actual )
354+
355+ # Ensure payload can be serialized to JSON
356+ json_str = json .dumps (mismatch .payload )
357+
358+ # Ensure it can be parsed back
359+ parsed = json .loads (json_str )
360+
361+ # Verify expected fields are present and are strings
362+ self .assertIn ('rationale' , parsed )
363+ self .assertIn ('expected' , parsed )
364+ self .assertIn ('actual' , parsed )
365+
366+ # Ensure values in payload are strings, not class types
367+ self .assertIsInstance (parsed ['expected' ], str )
368+ self .assertIsInstance (parsed ['actual' ], str )
369+
370+ def test_mismatch_with_help (self ):
371+ """Test that help messages are included in the payload."""
372+ import json
373+
374+ mismatch = check50 .Mismatch ("expected" , "actual" , help = "Did you forget something?" )
375+
376+ # Ensure payload can be serialized to JSON
377+ json_str = json .dumps (mismatch .payload )
378+ parsed = json .loads (json_str )
379+
380+ # Verify help is in the payload
381+ self .assertEqual (parsed ['help' ], "Did you forget something?" )
382+
383+ def test_mismatch_with_truncation (self ):
384+ """Test that long strings are truncated properly."""
385+ import json
386+
387+ # Create very long strings that will be truncated
388+ long_expected = "a" * 1000
389+ long_actual = "b" * 1000
390+
391+ mismatch = check50 .Mismatch (long_expected , long_actual )
392+
393+ # Ensure payload can be serialized to JSON
394+ json_str = json .dumps (mismatch .payload )
395+ parsed = json .loads (json_str )
396+
397+ # Verify truncation occurred (should have ellipsis)
398+ self .assertIn ("..." , parsed ['expected' ])
399+ self .assertIn ("..." , parsed ['actual' ])
400+
297401if __name__ == '__main__' :
298402 unittest .main ()
0 commit comments