diff --git a/Lib/test/test_json/test_tool.py b/Lib/test/test_json/test_tool.py index 0a96b318b15b1c..386409b966834a 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py @@ -8,7 +8,7 @@ from test import support from test.support import force_colorized, force_not_colorized, os_helper -from test.support.script_helper import assert_python_ok +from test.support.script_helper import assert_python_failure, assert_python_ok from _colorize import get_theme @@ -327,6 +327,92 @@ def test_colors(self): stdout = stdout.strip() self.assertEqual(stdout, expected) + @force_not_colorized + def test_invalid_json_input(self): + # Malformed JSON on stdin: ValueError is reported on stderr and the + # process exits with status 1. + args = sys.executable, '-m', self.module + process = subprocess.run(args, input='not valid json', + capture_output=True, text=True) + self.assertEqual(process.returncode, 1) + self.assertEqual(process.stdout, '') + self.assertIn('Expecting value', process.stderr) + + @force_not_colorized + def test_empty_input(self): + # Empty stdin is treated as missing JSON value and reported as an + # error. + args = sys.executable, '-m', self.module + process = subprocess.run(args, input='', capture_output=True, + text=True) + self.assertEqual(process.returncode, 1) + self.assertEqual(process.stdout, '') + self.assertIn('Expecting value', process.stderr) + + def test_missing_infile(self): + infile = os_helper.TESTFN + '.does-not-exist' + rc, out, err = assert_python_failure('-m', self.module, infile, + PYTHON_COLORS='0') + self.assertNotEqual(rc, 0) + self.assertIn(b'FileNotFoundError', err) + + def test_unknown_option(self): + rc, out, err = assert_python_failure('-m', self.module, + '--bogus-option', + PYTHON_COLORS='0') + self.assertEqual(rc, 2) + self.assertIn(b'unrecognized arguments', err) + + def test_mutually_exclusive_indent_and_tab(self): + rc, out, err = assert_python_failure('-m', self.module, + '--indent', '2', '--tab', + PYTHON_COLORS='0') + self.assertEqual(rc, 2) + self.assertIn(b'not allowed with', err) + + def test_mutually_exclusive_compact_and_no_indent(self): + rc, out, err = assert_python_failure('-m', self.module, + '--compact', '--no-indent', + PYTHON_COLORS='0') + self.assertEqual(rc, 2) + self.assertIn(b'not allowed with', err) + + @force_not_colorized + def test_jsonlines_compact(self): + # --json-lines combined with --compact emits valid JSON Lines output: + # one compact JSON object per line. + expect = ('{"ingredients":["frog","water","chocolate","glucose"]}\n' + '{"ingredients":["chocolate","steel bolts"]}\n') + args = (sys.executable, '-m', self.module, + '--json-lines', '--compact') + process = subprocess.run(args, input=self.jsonlines_raw, + capture_output=True, text=True, check=True) + self.assertEqual(process.stdout, expect) + self.assertEqual(process.stderr, '') + + @force_not_colorized + def test_jsonlines_no_indent(self): + # --json-lines combined with --no-indent emits valid JSON Lines + # output: one single-line JSON object per line. + expect = ('{"ingredients": ["frog", "water", "chocolate", "glucose"]}\n' + '{"ingredients": ["chocolate", "steel bolts"]}\n') + args = (sys.executable, '-m', self.module, + '--json-lines', '--no-indent') + process = subprocess.run(args, input=self.jsonlines_raw, + capture_output=True, text=True, check=True) + self.assertEqual(process.stdout, expect) + self.assertEqual(process.stderr, '') + + @force_not_colorized + def test_jsonlines_invalid_line(self): + # An invalid line in --json-lines mode causes the command to fail + # after emitting any already-processed lines. + args = sys.executable, '-m', self.module, '--json-lines' + process = subprocess.run(args, input='{"a": 1}\nnot valid\n', + capture_output=True, text=True) + self.assertEqual(process.returncode, 1) + self.assertIn('Expecting value', process.stderr) + @support.requires_subprocess() @support.skip_if_pgo_task diff --git a/Misc/NEWS.d/next/Tests/2026-05-15-12-00-00.gh-issue-131178.json.rst b/Misc/NEWS.d/next/Tests/2026-05-15-12-00-00.gh-issue-131178.json.rst new file mode 100644 index 00000000000000..dee459839d4a5e --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-05-15-12-00-00.gh-issue-131178.json.rst @@ -0,0 +1,3 @@ +Add tests for the :mod:`json` command-line interface, covering error paths +(invalid JSON, missing input file, unknown and mutually exclusive options) +as well as ``--json-lines`` combined with ``--compact`` or ``--no-indent``.