|
| 1 | +from pathlib import Path |
| 2 | +import subprocess |
| 3 | +import sys |
| 4 | +import tempfile |
| 5 | +from types import SimpleNamespace |
| 6 | +import unittest |
| 7 | +from unittest.mock import patch |
| 8 | + |
| 9 | + |
| 10 | +sys.path.insert(0, str(Path(__file__).parent)) |
| 11 | +import verify_opencv as verifier |
| 12 | + |
| 13 | + |
| 14 | +class OpenCvVerificationTest(unittest.TestCase): |
| 15 | + def setUp(self): |
| 16 | + self.directory = tempfile.TemporaryDirectory() |
| 17 | + self.addCleanup(self.directory.cleanup) |
| 18 | + self.prefix = Path(self.directory.name) |
| 19 | + self.package = self.prefix / "lib" / "cv2" |
| 20 | + self.package.mkdir(parents=True) |
| 21 | + (self.package / "__init__.py").touch() |
| 22 | + (self.package / "cv2.test.so").touch() |
| 23 | + self.cv2 = SimpleNamespace(__file__=str(self.package / "__init__.py"), |
| 24 | + __version__="5.0.0", CAP_FFMPEG=1900, |
| 25 | + getBuildInformation=lambda: "Video I/O:\n Images: YES\n", |
| 26 | + videoio_registry=SimpleNamespace(getBackends=lambda: (2000, 2200), |
| 27 | + hasBackend=lambda value: False)) |
| 28 | + self.ldd = patch.object(verifier.subprocess, "run", return_value= |
| 29 | + subprocess.CompletedProcess([], 0, "libc.so.6 => /lib/libc.so.6", "")) |
| 30 | + self.ldd.start() |
| 31 | + self.addCleanup(self.ldd.stop) |
| 32 | + |
| 33 | + def test_missing_text_still_requires_registry_and_native_inspection(self): |
| 34 | + report = verifier.verify(self.cv2, self.prefix) |
| 35 | + self.assertFalse(report["ffmpegAvailable"]) |
| 36 | + self.assertEqual(report["nativeExtensions"], 1) |
| 37 | + self.assertEqual(report["ffmpegConfigurationValues"], []) |
| 38 | + verifier.subprocess.run.assert_called_once() |
| 39 | + |
| 40 | + def test_disabled_configuration_spellings(self): |
| 41 | + for value in ("NO", "OFF", "false", "DISABLED"): |
| 42 | + with self.subTest(value=value): |
| 43 | + self.cv2.getBuildInformation = lambda: f" FFmpeg: {value}\n" |
| 44 | + verifier.verify(self.cv2, self.prefix) |
| 45 | + |
| 46 | + def test_enabled_or_unknown_configuration_is_rejected(self): |
| 47 | + for value in ("YES", "ON", "true", "unknown"): |
| 48 | + with self.subTest(value=value): |
| 49 | + self.cv2.getBuildInformation = lambda: f" FFMPEG: {value}\n" |
| 50 | + with self.assertRaises(RuntimeError): |
| 51 | + verifier.verify(self.cv2, self.prefix) |
| 52 | + |
| 53 | + def test_registered_but_unavailable_backend_is_rejected(self): |
| 54 | + self.cv2.videoio_registry.getBackends = lambda: (1900, 2000) |
| 55 | + with self.assertRaisesRegex(RuntimeError, "registers"): |
| 56 | + verifier.verify(self.cv2, self.prefix) |
| 57 | + |
| 58 | + def test_available_backend_is_rejected(self): |
| 59 | + self.cv2.videoio_registry.hasBackend = lambda value: True |
| 60 | + with self.assertRaisesRegex(RuntimeError, "provides"): |
| 61 | + verifier.verify(self.cv2, self.prefix) |
| 62 | + |
| 63 | + def test_ffmpeg_library_or_plugin_is_rejected(self): |
| 64 | + for filename in ("libavcodec-a123.so.62", "libopencv_videoio_ffmpeg.so"): |
| 65 | + with self.subTest(filename=filename): |
| 66 | + library = self.prefix / filename |
| 67 | + library.touch() |
| 68 | + with self.assertRaisesRegex(RuntimeError, "packaged"): |
| 69 | + verifier.verify(self.cv2, self.prefix) |
| 70 | + library.unlink() |
| 71 | + |
| 72 | + def test_missing_or_ffmpeg_linked_dependencies_are_rejected(self): |
| 73 | + for output in ("libz.so.1 => not found", "libavutil.so.60 => /lib/libavutil.so.60"): |
| 74 | + with self.subTest(output=output): |
| 75 | + verifier.subprocess.run.return_value.stdout = output |
| 76 | + with self.assertRaisesRegex(RuntimeError, "dependencies"): |
| 77 | + verifier.verify(self.cv2, self.prefix) |
| 78 | + |
| 79 | + |
| 80 | +if __name__ == "__main__": |
| 81 | + unittest.main() |
0 commit comments