Skip to content

Commit 31c2aa7

Browse files
committed
gh-131178: Add tests for ftplib command-line interface
Add unit tests in Lib/test/test_ftplib.py covering the ftplib command-line interface: verifying usage message on empty invocation, subprocess invocation, host connection with debuglevel, directory and passive mode commands, file retrieval, and custom netrc file error handling.
1 parent 9c0cfb1 commit 31c2aa7

2 files changed

Lines changed: 66 additions & 0 deletions

File tree

‎Lib/test/test_ftplib.py‎

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,71 @@ def test__all__(self):
11911191
support.check__all__(self, ftplib, not_exported=not_exported)
11921192

11931193

1194+
class CommandLineTest(TestCase):
1195+
"""Tests for the ftplib command-line interface."""
1196+
1197+
def test_main_no_arguments_prints_usage(self):
1198+
with mock.patch('sys.argv', ['ftplib']), \
1199+
support.captured_stdout() as stdout:
1200+
with self.assertRaises(SystemExit) as cm:
1201+
ftplib.test()
1202+
self.assertEqual(cm.exception.code, 0)
1203+
output = stdout.getvalue()
1204+
self.assertIn('Usage:', output)
1205+
self.assertIn('Options:', output)
1206+
self.assertIn('Commands:', output)
1207+
1208+
@requires_subprocess
1209+
def test_subprocess_invocation_no_args(self):
1210+
from test.support.script_helper import assert_python_ok
1211+
rc, out, err = assert_python_ok('-m', 'ftplib')
1212+
self.assertEqual(rc, 0)
1213+
self.assertIn(b'Usage:', out)
1214+
self.assertIn(b'Options:', out)
1215+
self.assertIn(b'Commands:', out)
1216+
self.assertEqual(err, b'')
1217+
1218+
@mock.patch('ftplib.FTP')
1219+
def test_cli_host_and_debugging(self, mock_ftp_cls):
1220+
mock_ftp = mock_ftp_cls.return_value
1221+
with mock.patch('sys.argv', ['ftplib', '-d', '-d', 'example.com']):
1222+
ftplib.test()
1223+
mock_ftp_cls.assert_called_once_with('example.com')
1224+
mock_ftp.set_debuglevel.assert_called_once_with(2)
1225+
mock_ftp.login.assert_called_once_with('', '', '')
1226+
mock_ftp.quit.assert_called_once()
1227+
1228+
@mock.patch('ftplib.FTP')
1229+
def test_cli_commands(self, mock_ftp_cls):
1230+
mock_ftp = mock_ftp_cls.return_value
1231+
with mock.patch('sys.argv', ['ftplib', 'example.com', '-l/pub', '-d/incoming', '-p']):
1232+
ftplib.test()
1233+
mock_ftp_cls.assert_called_once_with('example.com')
1234+
mock_ftp.dir.assert_called_once_with('/pub')
1235+
mock_ftp.sendcmd.assert_called_once_with('CWD /incoming')
1236+
mock_ftp.set_pasv.assert_called_once_with(not mock_ftp.passiveserver)
1237+
mock_ftp.quit.assert_called_once()
1238+
1239+
@mock.patch('ftplib.FTP')
1240+
def test_cli_retrieve_file(self, mock_ftp_cls):
1241+
mock_ftp = mock_ftp_cls.return_value
1242+
with mock.patch('sys.argv', ['ftplib', 'example.com', 'testfile.txt']):
1243+
ftplib.test()
1244+
mock_ftp.retrbinary.assert_called_once()
1245+
args, kwargs = mock_ftp.retrbinary.call_args
1246+
self.assertEqual(args[0], 'RETR testfile.txt')
1247+
mock_ftp.quit.assert_called_once()
1248+
1249+
@mock.patch('ftplib.FTP')
1250+
@mock.patch('netrc.netrc', side_effect=OSError('file not found'))
1251+
def test_cli_custom_rcfile_error(self, mock_netrc, mock_ftp_cls):
1252+
with mock.patch('sys.argv', ['ftplib', '-rnonexistent.netrc', 'example.com']), \
1253+
support.captured_stderr() as stderr:
1254+
ftplib.test()
1255+
self.assertIn("Could not open account file -- using anonymous login.",
1256+
stderr.getvalue())
1257+
1258+
11941259
def setUpModule():
11951260
thread_info = threading_helper.threading_setup()
11961261
unittest.addModuleCleanup(threading_helper.threading_cleanup, *thread_info)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add tests for ``ftplib`` command-line interface.

0 commit comments

Comments
 (0)