Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

3 місяці тому
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. """test_feature_extractors.py - test pipeline feature extractors"""
  2. import unittest
  3. import os
  4. import pytest
  5. import pipeline.feature_extractors as extractors
  6. from pipeline.utils import Source, SourceMedia # technically makes this an integration test, but...
  7. class TestSource():
  8. """Provide utils.Source for testing"""
  9. def one_colour_silent_audio(self):
  10. """Provide a source with a silent mono-colour video"""
  11. TEST_DIR = os.path.dirname(os.path.realpath(__file__))
  12. SAMPLE_VIDEO = f"{TEST_DIR}/sample_videos/test_video_red_silentaudio.mp4" # silent video definitely has no laughter
  13. return Source(source=SAMPLE_VIDEO, path=SAMPLE_VIDEO, provider="test")
  14. class TestSourceMedia():
  15. """Provide utils.SourceMedia for testing"""
  16. def one_colour_silent_audio(self):
  17. """Provide a source with a silent mono-colour video"""
  18. return SourceMedia(sources=[TestSource().one_colour_silent_audio()])
  19. class TestLaughterFeatureExtractor(unittest.TestCase):
  20. def _mock_laughdetect_callout(self, *args, **kwargs):
  21. """Mock _laughdetect callout
  22. **kwargs:
  23. - n : int >=0, number of laughter instances to generate
  24. Return a list of 2-tuple floats (start, end) representing laughter instances
  25. """
  26. laughs = []
  27. n = kwargs.get("n", 0)
  28. for i in range(n):
  29. laughs.append((i, i+1))
  30. return laughs
  31. def _mock_run_get_output(self, *args, **kwargs) -> str:
  32. """Mock run_get_output callout
  33. kwargs:
  34. - n : int >=0, number of laughter instances to generate
  35. Return a string of laughter instance of the form:
  36. instance: (1.234, 5.678)
  37. """
  38. # TODO: decide if we want non-"instance" output for testing parsing?
  39. # (maybe)
  40. output = []
  41. n = kwargs.get("n", 0)
  42. for i in range(n):
  43. output.append(f"instance: ({i}.{i+1}{i+2}{i+3}, {i+4}.{i+5}{i+6}{i+7})")
  44. return "\n".join(output)
  45. def _sgo5(self, *args, **kwargs):
  46. """Mock run_get_output callout"""
  47. return self._mock_run_get_output(*args, **kwargs, n=5)
  48. """Test LaughterFeatureExtractor"""
  49. def test_init(self):
  50. test_extractor = extractors.LaughterFeatureExtractor()
  51. self.assertTrue(test_extractor)
  52. def test_setup_noinput(self):
  53. """test setup - no input files"""
  54. test_extractor = extractors.LaughterFeatureExtractor()
  55. with self.assertRaises(ValueError):
  56. test_extractor.setup()
  57. # NB test WITH sources implicitly tested in test_extract
  58. @pytest.mark.slow
  59. def test_extract_mocked_nolaughs(self):
  60. """Test extract with mocked laughter detection - no laughs"""
  61. video_source = TestSource().one_colour_silent_audio()
  62. test_extractor = extractors.LaughterFeatureExtractor(input_files=[video_source])
  63. test_extractor._laughdetect = self._mock_laughdetect_callout
  64. test_extractor.setup()
  65. test_extractor.run()
  66. test_extractor.teardown()
  67. self.assertEqual(len(test_extractor.features), 0)
  68. def test_extract_mocked_run_get_output_none(self):
  69. """Test extract with mocked laughter detection - no laughs"""
  70. video_source = TestSource().one_colour_silent_audio()
  71. test_extractor = extractors.LaughterFeatureExtractor(input_files=[video_source])
  72. test_extractor._run_get_output = self._mock_run_get_output
  73. test_extractor.setup()
  74. test_extractor.run()
  75. test_extractor.teardown()
  76. self.assertEqual(len(test_extractor.features), 0)
  77. def test_extract_mocked_run_get_output_5(self):
  78. """Test extract with mocked laughter detection - 5 laughs"""
  79. video_source = TestSource().one_colour_silent_audio()
  80. test_extractor = extractors.LaughterFeatureExtractor(input_files=[video_source])
  81. test_extractor._run_get_output = self._sgo5
  82. test_extractor.setup()
  83. test_extractor.run()
  84. test_extractor.teardown()
  85. self.assertEqual(len(test_extractor.features), 5)
  86. def test_run_get_output(self):
  87. """Test run_get_output"""
  88. video_source = TestSource().one_colour_silent_audio()
  89. test_extractor = extractors.LaughterFeatureExtractor(input_files=[video_source])
  90. test_cmd = ["echo", "foo"]
  91. test_extractor.setup()
  92. output = test_extractor._run_get_output(test_cmd)
  93. self.assertEqual(output, "foo\n")
  94. # TODO: add sample video with laughs to test _laughdetect()
  95. class TestRandomFeatureExtractor(unittest.TestCase):
  96. """Test RandomFeatureExtractor"""
  97. def test_init(self):
  98. test_extractor = extractors.RandomFeatureExtractor()
  99. self.assertTrue(test_extractor)
  100. def test_setup_noinput(self):
  101. """test setup - no input files"""
  102. test_extractor = extractors.RandomFeatureExtractor()
  103. with self.assertRaises(ValueError):
  104. test_extractor.setup()
  105. # NB test WITH sources implicitly tested in test_extract
  106. def test_extract_noinput(self):
  107. """Test extract with no input files"""
  108. test_extractor = extractors.RandomFeatureExtractor()
  109. with self.assertRaises(ValueError):
  110. test_extractor.run()
  111. def test_extract(self):
  112. """Test extract with input files"""
  113. video_source = TestSourceMedia().one_colour_silent_audio()
  114. test_extractor = extractors.RandomFeatureExtractor(input_files=video_source)
  115. test_extractor.setup()
  116. test_extractor.run()
  117. test_extractor.teardown()
  118. self.assertTrue(test_extractor.features)
  119. class TestLoudAudioFeatureExtractor(unittest.TestCase):
  120. """Test LoudAudioFeatureExtractor"""
  121. def test_init(self):
  122. video_source = TestSourceMedia().one_colour_silent_audio()
  123. test_extractor = extractors.LoudAudioFeatureExtractor(input_files=video_source)
  124. self.assertTrue(test_extractor)
  125. def test_init_noinput(self):
  126. """test init - no input files"""
  127. with self.assertRaises(ValueError):
  128. test_extractor = extractors.LoudAudioFeatureExtractor()
  129. def test_extract(self):
  130. """Test extract with input files"""
  131. video_source = TestSourceMedia().one_colour_silent_audio()
  132. test_extractor = extractors.LoudAudioFeatureExtractor(input_files=video_source)
  133. test_extractor.setup()
  134. test_extractor.run()
  135. test_extractor.teardown()
  136. self.assertEqual(test_extractor.features, [])
  137. class TestVideoActivityFeatureExtractor(unittest.TestCase):
  138. """Test VideoActivityFeatureExtractor"""
  139. def test_init(self):
  140. video_source = TestSourceMedia().one_colour_silent_audio()
  141. test_extractor = extractors.VideoActivityFeatureExtractor(input_files=video_source)
  142. self.assertTrue(test_extractor)
  143. def test_init_noinput(self):
  144. """test init - no input files"""
  145. with self.assertRaises(ValueError):
  146. test_extractor = extractors.VideoActivityFeatureExtractor()
  147. def test_extract(self):
  148. """Test extract with basic input file runs with no errors"""
  149. video_source = TestSourceMedia().one_colour_silent_audio()
  150. test_extractor = extractors.VideoActivityFeatureExtractor(input_files=video_source)
  151. test_extractor.setup()
  152. test_extractor.run()
  153. test_extractor.teardown()
  154. self.assertTrue(test_extractor.features)
  155. # TODO: add sample video with activity to test _activitydetect()