|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- """Test cases for utils"""
- import unittest
-
- import pipeline.utils as utils
-
- class MockSource():
- """Mock Source object for testing Feature"""
- def __init__(self, source):
- self.source = source
-
- def __str__(self):
- return self.source
-
- def to_json(self):
- return {"source": self.source}
-
- def __eq__(self, other):
- return self.source == other.source
-
- class MockInterval():
- """Mock Interval object for testing Feature"""
- def __init__(self, start, end):
- self.start = start
- self.end = end
-
- def to_json(self):
- return {"start": self.start, "end": self.end}
-
- class TestSource(unittest.TestCase):
- """Source is a container for source, path, and provider of a media file
-
- source -- the source of the media file (eg, a URL or a local path)
- path -- the path to the media file
- provider -- the provider of the media file (eg, "FileInputJSON")
-
- Accessing the object should return the path to the media file.
-
- Methods:
-
- duration() -- return the duration of the media file (uses ffprobe, result is cached)
- """
- # Happy path tests
- def setUp(self):
- self.source = "audio_clips/testclip-5min.aac"
- self.path = "audio_clips/testclip-5min.aac"
- self.provider = "FileInputJSON"
- self._duration = 306.121214 # duration of testclip-5min.aac
-
- def test_init(self):
- source = utils.Source(self.source, self.path, self.provider)
- self.assertEqual(source.source, self.source)
- self.assertEqual(source.path, self.path)
- self.assertEqual(source.provider, self.provider)
-
- def test_str(self):
- """Accessing the object should return the path to the media file"""
- source = utils.Source(self.source, self.path, self.provider)
- self.assertEqual(str(source), self.path)
-
- def test_repr(self):
- source = utils.Source(self.source, self.path, self.provider)
- self.assertEqual(repr(source), f"Source({self.source}, {self.path}, {self.provider})")
-
- def test_duration(self):
- """Use a mock duration of 306.121214 for the test clip"""
- source = utils.Source(self.source, self.path, self.provider)
- self.assertEqual(source.duration(), self._duration)
-
- def test_to_json(self):
- source = utils.Source(self.source, self.path, self.provider)
- self.assertEqual(source.to_json(), {"source": self.source, "path": self.path, "provider": self.provider})
-
- # Sad path tests
- def test_init_no_source(self):
- with self.assertRaises(ValueError):
- utils.Source("", self.path, self.provider)
-
- def test_init_no_path(self):
- with self.assertRaises(ValueError):
- utils.Source(self.source, "", self.provider)
-
- def test_init_no_provider(self):
- with self.assertRaises(ValueError):
- utils.Source(self.source, self.path, "")
-
- def test_duration_no_file(self):
- """Test that duration raises FileNotFoundError if the file does not exist"""
- source = utils.Source(self.source, "fakepath-noexist!😇", self.provider)
- # if that file actually exists I'll eat my hat
- with self.assertRaises(FileNotFoundError):
- source.duration()
-
-
- class TestSourceMedia(unittest.TestCase):
- """SourceMedia is a container for Source objects"""
- class FakeSource():
- """Fake source object for testing SourceMedia
-
- Since SourceMedia doesn't actually access any of the attributes of Source objects,
- we can use a very empty class for testing.
- """
-
- def setUp(self):
- self.source1 = self.FakeSource()
- self.source2 = self.FakeSource()
- self.source3 = self.FakeSource()
- self.sources = [self.source1, self.source2, self.source3]
-
- def test_init(self):
- source_media = utils.SourceMedia(sources=self.sources)
- self.assertEqual(source_media.sources, self.sources)
-
- def test_iter(self):
- source_media = utils.SourceMedia(sources=self.sources)
- self.assertEqual(list(source_media), self.sources)
-
-
- class TestInterval(unittest.TestCase):
- """Interval is a container for start, end and duration attributes"""
- def setUp(self):
- self.start = 0
- self.end = 10
- self.duration = 10
-
- # Happy path tests
-
- def test_init_start_end(self):
- """Create an Interval using start and end attributes"""
- interval = utils.Interval(start=self.start, end=self.end)
- self.assertEqual(interval.start, self.start)
- self.assertEqual(interval.end, self.end)
- self.assertEqual(interval.duration, self.duration)
-
- def test_init_start_duration(self):
- """Create an Interval using start and duration attributes"""
- interval = utils.Interval(start=self.start, duration=self.duration)
- self.assertEqual(interval.start, self.start)
- self.assertEqual(interval.end, self.end)
- self.assertEqual(interval.duration, self.duration)
-
- def test_init_end_duration(self):
- """Create an Interval using end and duration attributes"""
- interval = utils.Interval(end=self.end, duration=self.duration)
- self.assertEqual(interval.start, self.start)
- self.assertEqual(interval.end, self.end)
- self.assertEqual(interval.duration, self.duration)
-
- def test_from_start_classmethod(self):
- """Create an Interval using the from_start classmethod (ie start attribute only- uses default duration)"""
- interval = utils.Interval.from_start(start=self.start)
- self.assertEqual(interval.start, self.start)
- self.assertEqual(interval.end, interval.start + utils.Interval.DEFAULT_DURATION)
- self.assertEqual(interval.duration, utils.Interval.DEFAULT_DURATION)
-
- def test_from_end_classmethod(self):
- """Create an Interval using the from_end classmethod (ie end attribute only- uses default duration)"""
- interval = utils.Interval.from_end(end=self.end)
- self.assertEqual(interval.start, interval.end - utils.Interval.DEFAULT_DURATION)
- self.assertEqual(interval.end, self.end)
- self.assertEqual(interval.duration, utils.Interval.DEFAULT_DURATION)
-
- def test_repr(self):
- interval = utils.Interval(start=self.start, end=self.end)
- self.assertEqual(repr(interval), f"Interval({self.start}, {self.end}, {self.duration})")
-
- def test_lt(self):
- """Test the __lt__ method used for sorting Interval objects based on start time
-
- If the start times are equal, the interval with the smaller end time is considered smaller
- """
- interval1 = utils.Interval(start=0, end=10)
- interval2 = utils.Interval(start=0, end=15)
- interval3 = utils.Interval(start=5, end=10)
- interval4 = utils.Interval(start=5, end=15)
- self.assertTrue(interval1 < interval2) # same start, interval1 has smaller end
- self.assertTrue(interval1 < interval3) # interval1 start is smaller
- self.assertTrue(interval3 > interval2) # interval3 start is larger
- self.assertTrue(interval3 < interval4) # same start, interval3 has smaller end
-
- def test_eq(self):
- """Test the __eq__ method for comparing Interval objects"""
- interval1 = utils.Interval(start=0, end=10)
- interval2 = utils.Interval(start=0, end=10)
- interval3 = utils.Interval(start=0, end=15)
- self.assertEqual(interval1, interval2)
- self.assertNotEqual(interval1, interval3)
-
- def test_to_json(self):
- """Test to_json method"""
- interval = utils.Interval(start=self.start, end=self.end)
- self.assertEqual(interval.to_json(), {"start": self.start, "end": self.end, "duration": self.duration})
-
- def test_move_start(self):
- """Test the move_start method - changes start time to time specified, keeps end time constant"""
- interval = utils.Interval(start=self.start, end=self.end)
- interval.move_start(5)
- self.assertEqual(interval.start, 5)
- self.assertEqual(interval.end, 10)
- self.assertEqual(interval.duration, 5)
-
- def test_move_start_relative(self):
- """Test the move_start method with relative=True - changes start time by a relative amount"""
- interval = utils.Interval(start=self.start, end=self.end)
- interval.move_start(2, relative=True)
- self.assertEqual(interval.start, 2)
- self.assertEqual(interval.end, 10)
- self.assertEqual(interval.duration, 8)
-
- def test_move_end(self):
- """Test the move_end method - changes end time to time specified, keeps start time constant"""
- interval = utils.Interval(start=self.start, end=self.end)
- interval.move_end(15)
- self.assertEqual(interval.start, 0)
- self.assertEqual(interval.end, 15)
- self.assertEqual(interval.duration, 15)
-
- def test_update_duration(self):
- """Test the update_duration method - changes duration to time specified, keeps start time constant"""
- interval = utils.Interval(start=self.start, end=self.end)
- interval.update_duration(15)
- self.assertEqual(interval.start, 0)
- self.assertEqual(interval.end, 15)
- self.assertEqual(interval.duration, 15)
- # test with relative=True
- interval.update_duration(5, relative=True)
- self.assertEqual(interval.start, 0)
-
- # Unhappy path tests
-
- def test_init_no_start_end(self):
- with self.assertRaises(ValueError):
- utils.Interval()
-
- def test_init_start_end_duration(self):
- with self.assertRaises(ValueError):
- utils.Interval(start=self.start, end=self.end, duration=self.duration)
-
- def test_init_start_after_end(self):
- with self.assertRaises(ValueError):
- utils.Interval(start=10, end=0)
-
- def test_init_negative_duration(self):
- with self.assertRaises(ValueError):
- utils.Interval(start=0, duration=-10)
- with self.assertRaises(ValueError):
- utils.Interval(end=0, duration=-10)
-
- class TestFeature(unittest.TestCase):
- """Test the Feature class"""
-
- # happy path tests
-
- def test_init(self):
- """Test creation of a Feature object.
-
- Needs: interval, source, feature_extractor and score"""
- source = MockSource("source")
- interval = MockInterval(0, 10)
- feature_extractor = "feature_extractor"
- score = 0.5
- feature = utils.Feature(interval, source, feature_extractor, score)
- # NOTE: LSP complains about assign MockSource to source, but it's fine
- self.assertEqual(feature.interval, interval)
- self.assertEqual(feature.source, source)
- self.assertEqual(feature.feature_extractor, feature_extractor)
- self.assertEqual(feature.score, score)
-
- def test_repr(self):
- source = MockSource("source")
- interval = MockInterval(0, 10)
- feature_extractor = "test"
- score = 0.5
- feature = utils.Feature(interval, source, feature_extractor, score)
- self.assertEqual(repr(feature), f"Feature({interval}, {source}, {feature_extractor}, {score})")
-
- def test_to_json(self):
- """test Feature.to_json method"""
- source = MockSource("source")
- interval = MockInterval(0, 10)
- feature_extractor = "test"
- score = 0.5
- feature = utils.Feature(interval, source, feature_extractor, score)
- self.assertEqual(feature.to_json(), {"interval": interval.to_json(), "source": source.to_json(),
- "feature_extractor": feature_extractor, "score": score})
-
- def test_classmethod_from_start(self):
- """Test the @classmethod for creating Feature with Interval.from_start"""
- source = MockSource("source")
- feature_extractor = "test"
- score = 0.5
- feature = utils.Feature.from_start(start=0, source=source, feature_extractor=feature_extractor, score=score)
- self.assertEqual(feature.interval.start, 0)
- self.assertEqual(feature.interval.end, 5)
- self.assertEqual(feature.interval.duration, 5)
- self.assertEqual(feature.source, source)
- self.assertEqual(feature.feature_extractor, feature_extractor)
- self.assertEqual(feature.score, score)
-
- def test_classmethod_from_end(self):
- """Test the @classmethod for creating Feature with Interval.from_end"""
- source = MockSource("source")
- feature_extractor = "test"
- score = 0.5
- feature = utils.Feature.from_end(end=10, source=source, feature_extractor=feature_extractor, score=score)
- self.assertEqual(feature.interval.start, 5)
- self.assertEqual(feature.interval.end, 10)
- self.assertEqual(feature.interval.duration, 5)
- self.assertEqual(feature.source, source)
- self.assertEqual(feature.feature_extractor, feature_extractor)
- self.assertEqual(feature.score, score)
-
- def test_lt(self):
- """test __lt__ method for sorting Feature objects"""
- # TODO: ensure goood coverage of corresponding __lt__ method of Interval
- feature1 = utils.Feature(utils.Interval(0, 10), MockSource("source"), "test_1", 0.5)
- feature2 = utils.Feature(utils.Interval(0, 15), MockSource("source"), "test_1", 0.5)
- feature3 = utils.Feature(utils.Interval(5, 10), MockSource("source"), "test_1", 0.5)
- feature4 = utils.Feature(utils.Interval(5, 15), MockSource("source"), "test_1", 0.5)
- feature5 = utils.Feature(utils.Interval(0, 10), MockSource("source"), "test_1", 0.6) # score
- feature6 = utils.Feature(utils.Interval(0, 10), MockSource("source"), "test_2", 0.5) # feature_extractor
-
- # test sorting based on Interval
- self.assertTrue(feature1 < feature2)
- self.assertTrue(feature1 < feature3)
- self.assertTrue(feature3 < feature4)
-
- # test sorting based on feature_extractor
- self.assertTrue(feature1 < feature6)
-
- # test sorting based on score
- self.assertTrue(feature1 < feature5)
-
- def test_eq(self):
- """test __eq__ method for comparing Feature objects"""
- feature1 = utils.Feature(utils.Interval(0, 10), MockSource("source"), "test_1", 0.5)
- feature2 = utils.Feature(utils.Interval(0, 10), MockSource("source"), "test_1", 0.5)
- feature3 = utils.Feature(utils.Interval(0, 10), MockSource("source"), "test_1", 0.6)
- self.assertEqual(feature1, feature2)
- self.assertNotEqual(feature1, feature3)
-
- # unhappy path tests
-
- def test_init_unhappy(self):
- """Test init with pats missing"""
- with self.assertRaises(ValueError):
- utils.Feature(None, None, None, None)
-
- # missing interval
- with self.assertRaises(ValueError):
- utils.Feature(None, MockSource("source"), "feature_extractor", 0.5)
-
- # missing source
- with self.assertRaises(ValueError):
- utils.Feature(MockInterval(0, 10), None, "feature_extractor", 0.5)
-
- # missing feature_extractor
- feature = utils.Feature(MockInterval(0, 10), MockSource("source"), None, 0.5)
- self.assertEqual(feature.feature_extractor, "unknown")
-
- if __name__ == "__main__":
- unittest.main()
|