From 4712b6313a4e4ee137303b9bb8df86e577069fc6 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Sat, 18 Jul 2026 16:09:34 +0300 Subject: [PATCH 1/5] gh-153953: Increase test coverage for the wave module Add tests for previously-uncovered paths in Lib/wave.py, all reachable through the public API: * Wave_write parameter validation: rejecting bad channel counts, sample widths, compression types and formats; the "not set" errors from the getters; the "cannot change parameters after starting to write" guards on every setter; and tell(). * Wave_read error handling: rejecting an unknown WAVE_FORMAT_EXTENSIBLE subformat, raising EOFError on a truncated fmt chunk, skipping unknown chunks, getfp(), and closing the file when opening a malformed path fails. * wave.open() rejecting an invalid mode. This raises line coverage of Lib/wave.py under test_wave from 317 to 345 of 449 executable lines. Test-only change; no behavior change. --- Lib/test/test_wave.py | 167 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py index d3723c04820d9d4..fb04bdae528715d 100644 --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -475,5 +475,172 @@ def test_open_pathlike(self): pass +class WaveReadErrorTest(unittest.TestCase): + """Cover error and edge paths of Wave_read, _Chunk and wave.open().""" + + FMT_PCM = struct.pack(' Date: Sun, 19 Jul 2026 02:32:06 +0300 Subject: [PATCH 2/5] Update Lib/test/test_wave.py Co-authored-by: Victor Stinner --- Lib/test/test_wave.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py index fb04bdae528715d..0c7078c7dc23104 100644 --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -531,10 +531,14 @@ def test_read_skips_unknown_chunk(self): self.assertEqual(r.getnframes(), 4) self.assertEqual(r.readframes(4), data) - def test_getfp_returns_underlying_file(self): + def test_getfp(self): b = self._wave_file((b'fmt ', self.FMT_PCM), (b'data', b'')) - with wave.open(io.BytesIO(b)) as r: - self.assertIsNotNone(r.getfp()) + fp = io.BytesIO(b) + with wave.open(fp) as r: + chunk = r.getfp() + self.assertIsNotNone(chunk) + self.assertIs(chunk.file, fp) + self.assertEqual(chunk.chunkname, b'RIFF') def test_open_invalid_mode(self): with self.assertRaisesRegex(wave.Error, "mode must be"): From e2019ff770fa8216e514cbf4d68eda287a917bb6 Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Sun, 19 Jul 2026 02:36:17 +0300 Subject: [PATCH 3/5] changed tests based on comments by vstinner --- Lib/test/test_wave.py | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py index 0c7078c7dc23104..9934c09272ca3bc 100644 --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -172,6 +172,15 @@ def test__all__(self): not_exported = {'KSDATAFORMAT_SUBTYPE_PCM'} support.check__all__(self, wave, not_exported=not_exported) + def test_getfp(self): + b = self._wave_file((b'fmt ', self.FMT_PCM), (b'data', b'')) + fp = io.BytesIO(b) + with wave.open(fp) as r: + chunk = r.getfp() + self.assertIsNotNone(chunk) + self.assertIs(chunk.file, fp) + self.assertEqual(chunk.chunkname, b'RIFF') + class WaveLowLevelTest(unittest.TestCase): @@ -473,6 +482,10 @@ def test_open_pathlike(self): with wave.open(fake_path, 'rb') as f: pass + + def test_open_invalid_mode(self): + with self.assertRaisesRegex(wave.Error, "mode must be"): + wave.open(io.BytesIO(), 'xb') class WaveReadErrorTest(unittest.TestCase): @@ -531,29 +544,6 @@ def test_read_skips_unknown_chunk(self): self.assertEqual(r.getnframes(), 4) self.assertEqual(r.readframes(4), data) - def test_getfp(self): - b = self._wave_file((b'fmt ', self.FMT_PCM), (b'data', b'')) - fp = io.BytesIO(b) - with wave.open(fp) as r: - chunk = r.getfp() - self.assertIsNotNone(chunk) - self.assertIs(chunk.file, fp) - self.assertEqual(chunk.chunkname, b'RIFF') - - def test_open_invalid_mode(self): - with self.assertRaisesRegex(wave.Error, "mode must be"): - wave.open(io.BytesIO(), 'xb') - - def test_open_path_closes_file_on_error(self): - # When opening by path fails to parse, the file we opened is closed - # and the parse error is propagated. - with tempfile.NamedTemporaryFile(delete=False) as fp: - fp.write(b'not a wave file') - filename = fp.name - self.addCleanup(unlink, filename) - with self.assertRaises(wave.Error): - wave.open(filename, 'rb') - class WaveWriteValidationTest(unittest.TestCase): """Cover parameter-validation paths of Wave_write.""" From 28c5f9c2fcf6600075e13db6e78b6b67d7553c3d Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Sun, 19 Jul 2026 13:34:46 +0300 Subject: [PATCH 4/5] gh-153953: Fix test_getfp after moving it to MiscTestCase The test relied on the _wave_file helper and FMT_PCM constant, which only exist on WaveReadErrorTest. Build the WAVE file with the wave module so the test is self-contained. --- Lib/test/test_wave.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py index 9934c09272ca3bc..1efa8e3b485b4f7 100644 --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -173,8 +173,12 @@ def test__all__(self): support.check__all__(self, wave, not_exported=not_exported) def test_getfp(self): - b = self._wave_file((b'fmt ', self.FMT_PCM), (b'data', b'')) - fp = io.BytesIO(b) + fp = io.BytesIO() + with wave.open(fp, 'wb') as w: + w.setnchannels(1) + w.setsampwidth(1) + w.setframerate(11025) + fp.seek(0) with wave.open(fp) as r: chunk = r.getfp() self.assertIsNotNone(chunk) From 2ce387f52caa7b00e798981e2cf011809115cc5a Mon Sep 17 00:00:00 2001 From: Vyron Vasileiadis Date: Sun, 19 Jul 2026 13:42:00 +0300 Subject: [PATCH 5/5] removes trailing whitespace --- Lib/test/test_wave.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py index 1efa8e3b485b4f7..0832e2a2db5d253 100644 --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -486,7 +486,7 @@ def test_open_pathlike(self): with wave.open(fake_path, 'rb') as f: pass - + def test_open_invalid_mode(self): with self.assertRaisesRegex(wave.Error, "mode must be"): wave.open(io.BytesIO(), 'xb')