Skip to content

Commit 1b05b9e

Browse files
committed
gh-131178: add tests for cProfile command-line interface
The existing TestCommandLine class only had two tests (invalid sort option and __main__ namespace). This expands coverage to exercise all major CLI code paths: - help output (-h/--help) - no arguments (usage + exit code 2) - unknown option (error + exit code 2) - invalid sort option (error + exit code 2) - valid sort options with both -s and --sort forms - output file with both -o and --outfile forms - profiling a script file - profiling a module via -m - nonexistent script file (FileNotFoundError)
1 parent 2f7634c commit 1b05b9e

File tree

1 file changed

+72
-3
lines changed

1 file changed

+72
-3
lines changed

Lib/test/test_profiling/test_tracing_profiler.py

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,80 @@ def test_bad_descriptor(self):
152152

153153

154154
class TestCommandLine(unittest.TestCase):
155-
def test_sort(self):
156-
rc, out, err = assert_python_failure('-m', 'cProfile', '-s', 'demo')
157-
self.assertGreater(rc, 0)
155+
def test_help(self):
156+
for flag in ('-h', '--help'):
157+
with self.subTest(flag=flag):
158+
_, out, _ = assert_python_ok('-m', 'cProfile', flag)
159+
self.assertIn(b'Usage: cProfile.py', out)
160+
self.assertIn(b'-o OUTFILE', out)
161+
self.assertIn(b'-s SORT', out)
162+
163+
def test_no_args(self):
164+
rc, out, _ = assert_python_failure('-m', 'cProfile')
165+
self.assertEqual(rc, 2)
166+
self.assertIn(b'Usage: cProfile.py', out)
167+
168+
def test_unknown_option(self):
169+
rc, _, err = assert_python_failure('-m', 'cProfile', '--unknown')
170+
self.assertEqual(rc, 2)
171+
self.assertIn(b'no such option', err)
172+
173+
def test_invalid_sort(self):
174+
rc, _, err = assert_python_failure('-m', 'cProfile', '-s', 'demo')
175+
self.assertEqual(rc, 2)
158176
self.assertIn(b"option -s: invalid choice: 'demo'", err)
159177

178+
def test_valid_sort(self):
179+
with tempfile.NamedTemporaryFile("w", suffix=".py",
180+
delete_on_close=False) as f:
181+
f.write("def f(): pass\nf()\n")
182+
f.close()
183+
for sort_key in ('calls', 'cumtime', 'tottime', 'name'):
184+
for flag in ('-s', '--sort'):
185+
with self.subTest(sort_key=sort_key, flag=flag):
186+
_, out, _ = assert_python_ok(
187+
'-m', 'cProfile', flag, sort_key, f.name
188+
)
189+
self.assertIn(b'function calls', out)
190+
191+
def test_outfile(self):
192+
with tempfile.NamedTemporaryFile("w", suffix=".py",
193+
delete_on_close=False) as script:
194+
script.write("def f(): pass\nf()\n")
195+
script.close()
196+
outfile = tempfile.NamedTemporaryFile(delete=False)
197+
outfile.close()
198+
self.addCleanup(support.os_helper.unlink, outfile.name)
199+
for flag in ('-o', '--outfile'):
200+
with self.subTest(flag=flag):
201+
assert_python_ok(
202+
'-m', 'cProfile', flag, outfile.name, script.name
203+
)
204+
with open(outfile.name, 'rb') as f:
205+
self.assertGreater(len(f.read()), 0)
206+
207+
def test_profile_script(self):
208+
with tempfile.NamedTemporaryFile("w", suffix=".py",
209+
delete_on_close=False) as f:
210+
f.write("def f(): pass\nf()\n")
211+
f.close()
212+
_, out, _ = assert_python_ok('-m', 'cProfile', f.name)
213+
self.assertIn(b'function calls', out)
214+
self.assertIn(b'Ordered by', out)
215+
216+
def test_profile_module(self):
217+
_, out, _ = assert_python_ok(
218+
'-m', 'cProfile', '-m', 'timeit', '-n', '1', 'pass'
219+
)
220+
self.assertIn(b'function calls', out)
221+
222+
def test_nonexistent_script(self):
223+
rc, _, err = assert_python_failure(
224+
'-m', 'cProfile', 'nonexistent_script.py'
225+
)
226+
self.assertEqual(rc, 1)
227+
self.assertIn(b'No such file or directory', err)
228+
160229
def test_profile_script_importing_main(self):
161230
"""Check that scripts that reference __main__ see their own namespace
162231
when being profiled."""

0 commit comments

Comments
 (0)