From 1e1514fbfb8498506987a4738f3e3f59cd44caf6 Mon Sep 17 00:00:00 2001 From: floor-licker Date: Mon, 24 Feb 2025 20:02:28 -0500 Subject: [PATCH 01/11] Create WinGetpassTest class --- Lib/test/test_getpass.py | 59 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/Lib/test/test_getpass.py b/Lib/test/test_getpass.py index 80dda2caaa3331..c63106cb076569 100644 --- a/Lib/test/test_getpass.py +++ b/Lib/test/test_getpass.py @@ -162,5 +162,64 @@ def test_falls_back_to_stdin(self): self.assertIn('Password:', stderr.getvalue()) +try: + import msvcrt + msvcrt = True +except ImportError: + msvcrt = False + +@unittest.skipUnless(msvcrt, 'tests require system with msvcrt (Windows)') +class WinGetpassTest(unittest.TestCase): + + def test_uses_msvcrt_directly(self): + # Mock the msvcrt.getch function to return a sequence ending with Enter key + with mock.patch('msvcrt.getch') as getch: + getch.side_effect = [b'a', b'b', b'c', b'\r'] + mock_stream = mock.Mock(spec=StringIO) + result = getpass.win_getpass(stream=mock_stream) + self.assertEqual(getch.call_count, 4) + self.assertEqual(result, 'abc') + # Check that the prompt was written to the stream + mock_stream.write.assert_any_call('Password: ') + # Check that the stream was flushed + mock_stream.flush.assert_called() + + def test_handles_backspace(self): + with mock.patch('msvcrt.getch') as getch, \ + mock.patch('msvcrt.putch') as putch: + getch.side_effect = [b'a', b'b', b'\b', b'c', b'\r'] + result = getpass.win_getpass() + self.assertEqual(result, 'ac') + # Verify putch was called to handle the backspace (erase character) + # The exact sequence depends on the implementation, but should include + # calls to handle the backspace character + putch.assert_any_call(b'\b') + + def test_handles_ctrl_c(self): + with mock.patch('msvcrt.getch') as getch: + # Simulate typing 'a' then Ctrl+C (ASCII value 3) + getch.side_effect = [b'a', b'\x03'] + # Verify that KeyboardInterrupt is raised + with self.assertRaises(KeyboardInterrupt): + getpass.win_getpass() + + def test_flushes_stream_after_input(self): + with mock.patch('msvcrt.getch') as getch: + # Simulate typing 'a' then Enter + getch.side_effect = [b'a', b'\r'] + mock_stream = mock.Mock(spec=StringIO) + getpass.win_getpass(stream=mock_stream) + mock_stream.flush.assert_called() + + def test_falls_back_to_fallback_if_msvcrt_raises(self): + with mock.patch('msvcrt.getch') as getch, \ + mock.patch('getpass.fallback_getpass') as fallback: + # Make getch raise an exception to trigger the fallback + getch.side_effect = RuntimeError("Simulated msvcrt failure") + mock_stream = mock.Mock(spec=StringIO) + getpass.win_getpass(stream=mock_stream) + fallback.assert_called_once_with('Password: ', mock_stream) + + if __name__ == "__main__": unittest.main() From 850a357adf7db013cb1574af0ed7f0fa4a987296 Mon Sep 17 00:00:00 2001 From: floor-licker Date: Mon, 24 Feb 2025 20:33:49 -0500 Subject: [PATCH 02/11] Fix linter error re: Redefinition of mscvrt --- Lib/test/test_getpass.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_getpass.py b/Lib/test/test_getpass.py index c63106cb076569..df9246bda2f9ae 100644 --- a/Lib/test/test_getpass.py +++ b/Lib/test/test_getpass.py @@ -164,11 +164,11 @@ def test_falls_back_to_stdin(self): try: import msvcrt - msvcrt = True + msvcrt_available = True except ImportError: - msvcrt = False + msvcrt_available = False -@unittest.skipUnless(msvcrt, 'tests require system with msvcrt (Windows)') +@unittest.skipUnless(msvcrt_available, 'tests require system with msvcrt (Windows)') class WinGetpassTest(unittest.TestCase): def test_uses_msvcrt_directly(self): From 15cb9a80df9f0f60e562928392e3220f32cad74c Mon Sep 17 00:00:00 2001 From: floor-licker Date: Mon, 24 Feb 2025 20:56:55 -0500 Subject: [PATCH 03/11] Add proper Windows-specific unittest decorator --- Lib/test/test_getpass.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_getpass.py b/Lib/test/test_getpass.py index df9246bda2f9ae..6f80169b32d29d 100644 --- a/Lib/test/test_getpass.py +++ b/Lib/test/test_getpass.py @@ -168,6 +168,7 @@ def test_falls_back_to_stdin(self): except ImportError: msvcrt_available = False +@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows") @unittest.skipUnless(msvcrt_available, 'tests require system with msvcrt (Windows)') class WinGetpassTest(unittest.TestCase): From 023c77db34f432911843e678ea2cf73217a66929 Mon Sep 17 00:00:00 2001 From: floor-licker Date: Mon, 24 Feb 2025 21:24:56 -0500 Subject: [PATCH 04/11] Try alternate Windows-specific test decorator --- Lib/test/test_getpass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_getpass.py b/Lib/test/test_getpass.py index 6f80169b32d29d..eff1f754dd0150 100644 --- a/Lib/test/test_getpass.py +++ b/Lib/test/test_getpass.py @@ -168,7 +168,7 @@ def test_falls_back_to_stdin(self): except ImportError: msvcrt_available = False -@unittest.skipUnless(sys.platform.startswith("win"), "requires Windows") +@unittest.skipUnless(WIN32, "skipped on non-Windows platforms") @unittest.skipUnless(msvcrt_available, 'tests require system with msvcrt (Windows)') class WinGetpassTest(unittest.TestCase): From b2e44fcf25861c0f9286d1f480db5a95ad92db5d Mon Sep 17 00:00:00 2001 From: floor-licker Date: Mon, 24 Feb 2025 23:37:28 -0500 Subject: [PATCH 05/11] Fixing name-error --- Lib/test/test_getpass.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_getpass.py b/Lib/test/test_getpass.py index eff1f754dd0150..1b952dfd7d0cc5 100644 --- a/Lib/test/test_getpass.py +++ b/Lib/test/test_getpass.py @@ -164,11 +164,12 @@ def test_falls_back_to_stdin(self): try: import msvcrt - msvcrt_available = True except ImportError: msvcrt_available = False +else: + msvcrt_available = True -@unittest.skipUnless(WIN32, "skipped on non-Windows platforms") +@unittest.skipUnless(support.MS_WINDOWS, "Windows-specific tests") @unittest.skipUnless(msvcrt_available, 'tests require system with msvcrt (Windows)') class WinGetpassTest(unittest.TestCase): From 730f8bc358a78aa966f0bb7279b78439b9d33a78 Mon Sep 17 00:00:00 2001 From: floor-licker Date: Tue, 25 Feb 2025 18:17:19 -0500 Subject: [PATCH 06/11] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_getpass.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/test/test_getpass.py b/Lib/test/test_getpass.py index 1b952dfd7d0cc5..a7c994c32125a6 100644 --- a/Lib/test/test_getpass.py +++ b/Lib/test/test_getpass.py @@ -202,8 +202,7 @@ def test_handles_ctrl_c(self): # Simulate typing 'a' then Ctrl+C (ASCII value 3) getch.side_effect = [b'a', b'\x03'] # Verify that KeyboardInterrupt is raised - with self.assertRaises(KeyboardInterrupt): - getpass.win_getpass() + self.assertRaises(KeyboardInterrupt, getpass.win_getpass) def test_flushes_stream_after_input(self): with mock.patch('msvcrt.getch') as getch: From e4dcd9366210ac6a2e78de61fb4f9331cbb0e180 Mon Sep 17 00:00:00 2001 From: floor-licker Date: Tue, 25 Feb 2025 18:23:49 -0500 Subject: [PATCH 07/11] picnixz suggestions --- Lib/test/test_getpass.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_getpass.py b/Lib/test/test_getpass.py index a7c994c32125a6..6b68be2851076c 100644 --- a/Lib/test/test_getpass.py +++ b/Lib/test/test_getpass.py @@ -14,6 +14,12 @@ except ImportError: pwd = None +try: + import msvcrt + +except ImportError: + mscvrt = None + @mock.patch('os.environ') class GetpassGetuserTest(unittest.TestCase): @@ -162,15 +168,8 @@ def test_falls_back_to_stdin(self): self.assertIn('Password:', stderr.getvalue()) -try: - import msvcrt -except ImportError: - msvcrt_available = False -else: - msvcrt_available = True - +@unittest.skipIf(msvcrt is None, 'tests require system with msvcrt (Windows)') @unittest.skipUnless(support.MS_WINDOWS, "Windows-specific tests") -@unittest.skipUnless(msvcrt_available, 'tests require system with msvcrt (Windows)') class WinGetpassTest(unittest.TestCase): def test_uses_msvcrt_directly(self): @@ -187,8 +186,10 @@ def test_uses_msvcrt_directly(self): mock_stream.flush.assert_called() def test_handles_backspace(self): - with mock.patch('msvcrt.getch') as getch, \ - mock.patch('msvcrt.putch') as putch: + with ( + mock.patch('msvcrt.getch') as getch, + mock.patch('msvcrt.putch') as putch, + ): getch.side_effect = [b'a', b'b', b'\b', b'c', b'\r'] result = getpass.win_getpass() self.assertEqual(result, 'ac') From 2bf440c71c3a4f95a63368513e98874ca857714a Mon Sep 17 00:00:00 2001 From: floor-licker Date: Tue, 25 Feb 2025 18:31:19 -0500 Subject: [PATCH 08/11] Update Lib/test/test_getpass.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_getpass.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_getpass.py b/Lib/test/test_getpass.py index 6b68be2851076c..ac018478e8de84 100644 --- a/Lib/test/test_getpass.py +++ b/Lib/test/test_getpass.py @@ -16,7 +16,6 @@ try: import msvcrt - except ImportError: mscvrt = None From ca46d3d2d53551373cf8da48b02d7c89eae95456 Mon Sep 17 00:00:00 2001 From: floor-licker Date: Tue, 25 Feb 2025 18:36:09 -0500 Subject: [PATCH 09/11] Maintain context manager syntax --- Lib/test/test_getpass.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_getpass.py b/Lib/test/test_getpass.py index ac018478e8de84..001a9d56b032e3 100644 --- a/Lib/test/test_getpass.py +++ b/Lib/test/test_getpass.py @@ -17,7 +17,7 @@ try: import msvcrt except ImportError: - mscvrt = None + msvcrt = None @mock.patch('os.environ') class GetpassGetuserTest(unittest.TestCase): @@ -185,16 +185,11 @@ def test_uses_msvcrt_directly(self): mock_stream.flush.assert_called() def test_handles_backspace(self): - with ( - mock.patch('msvcrt.getch') as getch, - mock.patch('msvcrt.putch') as putch, - ): + with mock.patch('msvcrt.getch') as getch, \ + mock.patch('msvcrt.putch') as putch: getch.side_effect = [b'a', b'b', b'\b', b'c', b'\r'] result = getpass.win_getpass() self.assertEqual(result, 'ac') - # Verify putch was called to handle the backspace (erase character) - # The exact sequence depends on the implementation, but should include - # calls to handle the backspace character putch.assert_any_call(b'\b') def test_handles_ctrl_c(self): @@ -214,8 +209,7 @@ def test_flushes_stream_after_input(self): def test_falls_back_to_fallback_if_msvcrt_raises(self): with mock.patch('msvcrt.getch') as getch, \ - mock.patch('getpass.fallback_getpass') as fallback: - # Make getch raise an exception to trigger the fallback + mock.patch('getpass.fallback_getpass') as fallback: getch.side_effect = RuntimeError("Simulated msvcrt failure") mock_stream = mock.Mock(spec=StringIO) getpass.win_getpass(stream=mock_stream) From 778e8397bbff5d556b3715866da3a683866638a5 Mon Sep 17 00:00:00 2001 From: floor-licker Date: Tue, 25 Feb 2025 18:40:41 -0500 Subject: [PATCH 10/11] Apply suggestions from code review Co-authored-by: donBarbos --- Lib/test/test_getpass.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/test/test_getpass.py b/Lib/test/test_getpass.py index 001a9d56b032e3..4e871ef5e2e741 100644 --- a/Lib/test/test_getpass.py +++ b/Lib/test/test_getpass.py @@ -167,8 +167,7 @@ def test_falls_back_to_stdin(self): self.assertIn('Password:', stderr.getvalue()) -@unittest.skipIf(msvcrt is None, 'tests require system with msvcrt (Windows)') -@unittest.skipUnless(support.MS_WINDOWS, "Windows-specific tests") +@unittest.skipUnless(msvcrt, 'tests require system with msvcrt') class WinGetpassTest(unittest.TestCase): def test_uses_msvcrt_directly(self): From 4e287cd440f7193da4aa59db088399e76ab3696d Mon Sep 17 00:00:00 2001 From: floor-licker Date: Wed, 26 Feb 2025 17:40:53 -0500 Subject: [PATCH 11/11] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_getpass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_getpass.py b/Lib/test/test_getpass.py index 4e871ef5e2e741..f3962c9854c72b 100644 --- a/Lib/test/test_getpass.py +++ b/Lib/test/test_getpass.py @@ -13,12 +13,12 @@ import pwd except ImportError: pwd = None - try: import msvcrt except ImportError: msvcrt = None + @mock.patch('os.environ') class GetpassGetuserTest(unittest.TestCase):