1import errno 2import os 3import sys 4import textwrap 5import unittest 6import subprocess 7 8from test import support 9from test.support import os_helper 10from test.support.script_helper import assert_python_ok 11 12 13@support.requires_subprocess() 14class TestTool(unittest.TestCase): 15 data = """ 16 17 [["blorpie"],[ "whoops" ] , [ 18 ],\t"d-shtaeou",\r"d-nthiouh", 19 "i-vhbjkhnth", {"nifty":87}, {"morefield" :\tfalse,"field" 20 :"yes"} ] 21 """ 22 23 expect_without_sort_keys = textwrap.dedent("""\ 24 [ 25 [ 26 "blorpie" 27 ], 28 [ 29 "whoops" 30 ], 31 [], 32 "d-shtaeou", 33 "d-nthiouh", 34 "i-vhbjkhnth", 35 { 36 "nifty": 87 37 }, 38 { 39 "field": "yes", 40 "morefield": false 41 } 42 ] 43 """) 44 45 expect = textwrap.dedent("""\ 46 [ 47 [ 48 "blorpie" 49 ], 50 [ 51 "whoops" 52 ], 53 [], 54 "d-shtaeou", 55 "d-nthiouh", 56 "i-vhbjkhnth", 57 { 58 "nifty": 87 59 }, 60 { 61 "morefield": false, 62 "field": "yes" 63 } 64 ] 65 """) 66 67 jsonlines_raw = textwrap.dedent("""\ 68 {"ingredients":["frog", "water", "chocolate", "glucose"]} 69 {"ingredients":["chocolate","steel bolts"]} 70 """) 71 72 jsonlines_expect = textwrap.dedent("""\ 73 { 74 "ingredients": [ 75 "frog", 76 "water", 77 "chocolate", 78 "glucose" 79 ] 80 } 81 { 82 "ingredients": [ 83 "chocolate", 84 "steel bolts" 85 ] 86 } 87 """) 88 89 def test_stdin_stdout(self): 90 args = sys.executable, '-m', 'json.tool' 91 process = subprocess.run(args, input=self.data, capture_output=True, text=True, check=True) 92 self.assertEqual(process.stdout, self.expect) 93 self.assertEqual(process.stderr, '') 94 95 def _create_infile(self, data=None): 96 infile = os_helper.TESTFN 97 with open(infile, "w", encoding="utf-8") as fp: 98 self.addCleanup(os.remove, infile) 99 fp.write(data or self.data) 100 return infile 101 102 def test_infile_stdout(self): 103 infile = self._create_infile() 104 rc, out, err = assert_python_ok('-m', 'json.tool', infile) 105 self.assertEqual(rc, 0) 106 self.assertEqual(out.splitlines(), self.expect.encode().splitlines()) 107 self.assertEqual(err, b'') 108 109 def test_non_ascii_infile(self): 110 data = '{"msg": "\u3053\u3093\u306b\u3061\u306f"}' 111 expect = textwrap.dedent('''\ 112 { 113 "msg": "\\u3053\\u3093\\u306b\\u3061\\u306f" 114 } 115 ''').encode() 116 117 infile = self._create_infile(data) 118 rc, out, err = assert_python_ok('-m', 'json.tool', infile) 119 120 self.assertEqual(rc, 0) 121 self.assertEqual(out.splitlines(), expect.splitlines()) 122 self.assertEqual(err, b'') 123 124 def test_infile_outfile(self): 125 infile = self._create_infile() 126 outfile = os_helper.TESTFN + '.out' 127 rc, out, err = assert_python_ok('-m', 'json.tool', infile, outfile) 128 self.addCleanup(os.remove, outfile) 129 with open(outfile, "r", encoding="utf-8") as fp: 130 self.assertEqual(fp.read(), self.expect) 131 self.assertEqual(rc, 0) 132 self.assertEqual(out, b'') 133 self.assertEqual(err, b'') 134 135 def test_writing_in_place(self): 136 infile = self._create_infile() 137 rc, out, err = assert_python_ok('-m', 'json.tool', infile, infile) 138 with open(infile, "r", encoding="utf-8") as fp: 139 self.assertEqual(fp.read(), self.expect) 140 self.assertEqual(rc, 0) 141 self.assertEqual(out, b'') 142 self.assertEqual(err, b'') 143 144 def test_jsonlines(self): 145 args = sys.executable, '-m', 'json.tool', '--json-lines' 146 process = subprocess.run(args, input=self.jsonlines_raw, capture_output=True, text=True, check=True) 147 self.assertEqual(process.stdout, self.jsonlines_expect) 148 self.assertEqual(process.stderr, '') 149 150 def test_help_flag(self): 151 rc, out, err = assert_python_ok('-m', 'json.tool', '-h') 152 self.assertEqual(rc, 0) 153 self.assertTrue(out.startswith(b'usage: ')) 154 self.assertEqual(err, b'') 155 156 def test_sort_keys_flag(self): 157 infile = self._create_infile() 158 rc, out, err = assert_python_ok('-m', 'json.tool', '--sort-keys', infile) 159 self.assertEqual(rc, 0) 160 self.assertEqual(out.splitlines(), 161 self.expect_without_sort_keys.encode().splitlines()) 162 self.assertEqual(err, b'') 163 164 def test_indent(self): 165 input_ = '[1, 2]' 166 expect = textwrap.dedent('''\ 167 [ 168 1, 169 2 170 ] 171 ''') 172 args = sys.executable, '-m', 'json.tool', '--indent', '2' 173 process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) 174 self.assertEqual(process.stdout, expect) 175 self.assertEqual(process.stderr, '') 176 177 def test_no_indent(self): 178 input_ = '[1,\n2]' 179 expect = '[1, 2]\n' 180 args = sys.executable, '-m', 'json.tool', '--no-indent' 181 process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) 182 self.assertEqual(process.stdout, expect) 183 self.assertEqual(process.stderr, '') 184 185 def test_tab(self): 186 input_ = '[1, 2]' 187 expect = '[\n\t1,\n\t2\n]\n' 188 args = sys.executable, '-m', 'json.tool', '--tab' 189 process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) 190 self.assertEqual(process.stdout, expect) 191 self.assertEqual(process.stderr, '') 192 193 def test_compact(self): 194 input_ = '[ 1 ,\n 2]' 195 expect = '[1,2]\n' 196 args = sys.executable, '-m', 'json.tool', '--compact' 197 process = subprocess.run(args, input=input_, capture_output=True, text=True, check=True) 198 self.assertEqual(process.stdout, expect) 199 self.assertEqual(process.stderr, '') 200 201 def test_no_ensure_ascii_flag(self): 202 infile = self._create_infile('{"key":""}') 203 outfile = os_helper.TESTFN + '.out' 204 self.addCleanup(os.remove, outfile) 205 assert_python_ok('-m', 'json.tool', '--no-ensure-ascii', infile, outfile) 206 with open(outfile, "rb") as f: 207 lines = f.read().splitlines() 208 # asserting utf-8 encoded output file 209 expected = [b'{', b' "key": "\xf0\x9f\x92\xa9"', b"}"] 210 self.assertEqual(lines, expected) 211 212 def test_ensure_ascii_default(self): 213 infile = self._create_infile('{"key":""}') 214 outfile = os_helper.TESTFN + '.out' 215 self.addCleanup(os.remove, outfile) 216 assert_python_ok('-m', 'json.tool', infile, outfile) 217 with open(outfile, "rb") as f: 218 lines = f.read().splitlines() 219 # asserting an ascii encoded output file 220 expected = [b'{', rb' "key": "\ud83d\udca9"', b"}"] 221 self.assertEqual(lines, expected) 222 223 @unittest.skipIf(sys.platform =="win32", "The test is failed with ValueError on Windows") 224 def test_broken_pipe_error(self): 225 cmd = [sys.executable, '-m', 'json.tool'] 226 proc = subprocess.Popen(cmd, 227 stdout=subprocess.PIPE, 228 stdin=subprocess.PIPE) 229 # bpo-39828: Closing before json.tool attempts to write into stdout. 230 proc.stdout.close() 231 proc.communicate(b'"{}"') 232 self.assertEqual(proc.returncode, errno.EPIPE) 233