diff options
Diffstat (limited to 'test')
26 files changed, 595 insertions, 210 deletions
| diff --git a/test/helper.py b/test/helper.py index 62cb3ce02..c416f388c 100644 --- a/test/helper.py +++ b/test/helper.py @@ -57,9 +57,9 @@ class FakeYDL(YoutubeDL):          # Different instances of the downloader can't share the same dictionary          # some test set the "sublang" parameter, which would break the md5 checks.          params = get_params(override=override) -        super(FakeYDL, self).__init__(params) +        super(FakeYDL, self).__init__(params, auto_init=False)          self.result = [] -         +      def to_screen(self, s, skip_eol=None):          print(s) @@ -72,32 +72,24 @@ class FakeYDL(YoutubeDL):      def expect_warning(self, regex):          # Silence an expected warning matching a regex          old_report_warning = self.report_warning +          def report_warning(self, message): -            if re.match(regex, message): return +            if re.match(regex, message): +                return              old_report_warning(message)          self.report_warning = types.MethodType(report_warning, self)  def gettestcases(include_onlymatching=False):      for ie in youtube_dl.extractor.gen_extractors(): -        t = getattr(ie, '_TEST', None) -        if t: -            assert not hasattr(ie, '_TESTS'), \ -                '%s has _TEST and _TESTS' % type(ie).__name__ -            tests = [t] -        else: -            tests = getattr(ie, '_TESTS', []) -        for t in tests: -            if not include_onlymatching and t.get('only_matching', False): -                continue -            t['name'] = type(ie).__name__[:-len('IE')] -            yield t +        for tc in ie.get_testcases(include_onlymatching): +            yield tc  md5 = lambda s: hashlib.md5(s.encode('utf-8')).hexdigest() -def expect_info_dict(self, expected_dict, got_dict): +def expect_info_dict(self, got_dict, expected_dict):      for info_field, expected in expected_dict.items():          if isinstance(expected, compat_str) and expected.startswith('re:'):              got = got_dict.get(info_field) @@ -114,14 +106,28 @@ def expect_info_dict(self, expected_dict, got_dict):          elif isinstance(expected, type):              got = got_dict.get(info_field)              self.assertTrue(isinstance(got, expected), -                'Expected type %r for field %s, but got value %r of type %r' % (expected, info_field, got, type(got))) +                            'Expected type %r for field %s, but got value %r of type %r' % (expected, info_field, got, type(got)))          else:              if isinstance(expected, compat_str) and expected.startswith('md5:'):                  got = 'md5:' + md5(got_dict.get(info_field)) +            elif isinstance(expected, compat_str) and expected.startswith('mincount:'): +                got = got_dict.get(info_field) +                self.assertTrue( +                    isinstance(got, list), +                    'Expected field %s to be a list, but it is of type %s' % ( +                        info_field, type(got).__name__)) +                expected_num = int(expected.partition(':')[2]) +                assertGreaterEqual( +                    self, len(got), expected_num, +                    'Expected %d items in field %s, but only got %d' % ( +                        expected_num, info_field, len(got) +                    ) +                ) +                continue              else:                  got = got_dict.get(info_field)              self.assertEqual(expected, got, -                'invalid value for field %s, expected %r, got %r' % (info_field, expected, got)) +                             'invalid value for field %s, expected %r, got %r' % (info_field, expected, got))      # Check for the presence of mandatory fields      if got_dict.get('_type') != 'playlist': @@ -133,19 +139,20 @@ def expect_info_dict(self, expected_dict, got_dict):      # Are checkable fields missing from the test case definition?      test_info_dict = dict((key, value if not isinstance(value, compat_str) or len(value) < 250 else 'md5:' + md5(value)) -        for key, value in got_dict.items() -        if value and key in ('title', 'description', 'uploader', 'upload_date', 'timestamp', 'uploader_id', 'location')) +                          for key, value in got_dict.items() +                          if value and key in ('title', 'description', 'uploader', 'upload_date', 'timestamp', 'uploader_id', 'location'))      missing_keys = set(test_info_dict.keys()) - set(expected_dict.keys())      if missing_keys:          def _repr(v):              if isinstance(v, compat_str): -                return "'%s'" % v.replace('\\', '\\\\').replace("'", "\\'") +                return "'%s'" % v.replace('\\', '\\\\').replace("'", "\\'").replace('\n', '\\n')              else:                  return repr(v)          info_dict_str = ''.join(              '    %s: %s,\n' % (_repr(k), _repr(v))              for k, v in test_info_dict.items()) -        write_string('\n"info_dict": {' + info_dict_str + '}\n', out=sys.stderr) +        write_string( +            '\n\'info_dict\': {\n' + info_dict_str + '}\n', out=sys.stderr)          self.assertFalse(              missing_keys,              'Missing keys in test definition: %s' % ( @@ -158,7 +165,9 @@ def assertRegexpMatches(self, text, regexp, msg=None):      else:          m = re.match(regexp, text)          if not m: -            note = 'Regexp didn\'t match: %r not found in %r' % (regexp, text) +            note = 'Regexp didn\'t match: %r not found' % (regexp) +            if len(text) < 1000: +                note += ' in %r' % text              if msg is None:                  msg = note              else: @@ -171,3 +180,13 @@ def assertGreaterEqual(self, got, expected, msg=None):          if msg is None:              msg = '%r not greater than or equal to %r' % (got, expected)          self.assertTrue(got >= expected, msg) + + +def expect_warnings(ydl, warnings_re): +    real_warning = ydl.report_warning + +    def _report_warning(w): +        if not any(re.search(w_re, w) for w_re in warnings_re): +            real_warning(w) + +    ydl.report_warning = _report_warning diff --git a/test/swftests/ConstArrayAccess.as b/test/swftests/ConstArrayAccess.as new file mode 100644 index 000000000..07dc3f460 --- /dev/null +++ b/test/swftests/ConstArrayAccess.as @@ -0,0 +1,18 @@ +// input: [] +// output: 4 + +package { +public class ConstArrayAccess { +	private static const x:int = 2; +	private static const ar:Array = ["42", "3411"]; + +    public static function main():int{ +        var c:ConstArrayAccess = new ConstArrayAccess(); +        return c.f(); +    } + +    public function f(): int { +    	return ar[1].length; +    } +} +} diff --git a/test/swftests/ConstantInt.as b/test/swftests/ConstantInt.as new file mode 100644 index 000000000..e0bbb6166 --- /dev/null +++ b/test/swftests/ConstantInt.as @@ -0,0 +1,12 @@ +// input: [] +// output: 2 + +package { +public class ConstantInt { +	private static const x:int = 2; + +    public static function main():int{ +        return x; +    } +} +} diff --git a/test/swftests/DictCall.as b/test/swftests/DictCall.as new file mode 100644 index 000000000..c2d174cc2 --- /dev/null +++ b/test/swftests/DictCall.as @@ -0,0 +1,10 @@ +// input: [{"x": 1, "y": 2}] +// output: 3 + +package { +public class DictCall { +    public static function main(d:Object):int{ +        return d.x + d.y; +    } +} +} diff --git a/test/swftests/EqualsOperator.as b/test/swftests/EqualsOperator.as new file mode 100644 index 000000000..837a69a46 --- /dev/null +++ b/test/swftests/EqualsOperator.as @@ -0,0 +1,10 @@ +// input: [] +// output: false + +package { +public class EqualsOperator { +    public static function main():Boolean{ +        return 1 == 2; +    } +} +} diff --git a/test/swftests/MemberAssignment.as b/test/swftests/MemberAssignment.as new file mode 100644 index 000000000..dcba5e3ff --- /dev/null +++ b/test/swftests/MemberAssignment.as @@ -0,0 +1,22 @@ +// input: [1] +// output: 2 + +package { +public class MemberAssignment { +    public var v:int; + +    public function g():int { +        return this.v; +    } + +    public function f(a:int):int{ +        this.v = a; +        return this.v + this.g(); +    } + +    public static function main(a:int): int { +        var v:MemberAssignment = new MemberAssignment(); +        return v.f(a); +    } +} +} diff --git a/test/swftests/NeOperator.as b/test/swftests/NeOperator.as new file mode 100644 index 000000000..61dcbc4e9 --- /dev/null +++ b/test/swftests/NeOperator.as @@ -0,0 +1,24 @@ +// input: [] +// output: 123 + +package { +public class NeOperator { +    public static function main(): int { +        var res:int = 0; +        if (1 != 2) { +            res += 3; +        } else { +            res += 4; +        } +        if (2 != 2) { +            res += 10; +        } else { +            res += 20; +        } +        if (9 == 9) { +            res += 100; +        } +        return res; +    } +} +} diff --git a/test/swftests/PrivateVoidCall.as b/test/swftests/PrivateVoidCall.as new file mode 100644 index 000000000..2cc016797 --- /dev/null +++ b/test/swftests/PrivateVoidCall.as @@ -0,0 +1,22 @@ +// input: [] +// output: 9 + +package { +public class PrivateVoidCall { +    public static function main():int{ +        var f:OtherClass = new OtherClass(); +        f.func(); +        return 9; +    } +} +} + +class OtherClass { +    private function pf():void { +        ; +    } + +    public function func():void { +        this.pf(); +    } +} diff --git a/test/swftests/StringBasics.as b/test/swftests/StringBasics.as new file mode 100644 index 000000000..d27430b13 --- /dev/null +++ b/test/swftests/StringBasics.as @@ -0,0 +1,11 @@ +// input: [] +// output: 3 + +package { +public class StringBasics { +    public static function main():int{ +        var s:String = "abc"; +        return s.length; +    } +} +} diff --git a/test/swftests/StringCharCodeAt.as b/test/swftests/StringCharCodeAt.as new file mode 100644 index 000000000..c20d74d65 --- /dev/null +++ b/test/swftests/StringCharCodeAt.as @@ -0,0 +1,11 @@ +// input: [] +// output: 9897 + +package { +public class StringCharCodeAt { +    public static function main():int{ +        var s:String = "abc"; +        return s.charCodeAt(1) * 100 + s.charCodeAt(); +    } +} +} diff --git a/test/swftests/StringConversion.as b/test/swftests/StringConversion.as new file mode 100644 index 000000000..c976f5042 --- /dev/null +++ b/test/swftests/StringConversion.as @@ -0,0 +1,11 @@ +// input: [] +// output: 2 + +package { +public class StringConversion { +    public static function main():int{ +        var s:String = String(99); +        return s.length; +    } +} +} diff --git a/test/test_InfoExtractor.py b/test/test_InfoExtractor.py index 13c18ed95..be8d12997 100644 --- a/test/test_InfoExtractor.py +++ b/test/test_InfoExtractor.py @@ -40,5 +40,23 @@ class TestInfoExtractor(unittest.TestCase):          self.assertEqual(ie._og_search_description(html), 'Some video\'s description ')          self.assertEqual(ie._og_search_thumbnail(html), 'http://domain.com/pic.jpg?key1=val1&key2=val2') +    def test_html_search_meta(self): +        ie = self.ie +        html = ''' +            <meta name="a" content="1" /> +            <meta name='b' content='2'> +            <meta name="c" content='3'> +            <meta name=d content='4'> +            <meta property="e" content='5' > +            <meta content="6" name="f"> +        ''' + +        self.assertEqual(ie._html_search_meta('a', html), '1') +        self.assertEqual(ie._html_search_meta('b', html), '2') +        self.assertEqual(ie._html_search_meta('c', html), '3') +        self.assertEqual(ie._html_search_meta('d', html), '4') +        self.assertEqual(ie._html_search_meta('e', html), '5') +        self.assertEqual(ie._html_search_meta('f', html), '6') +  if __name__ == '__main__':      unittest.main() diff --git a/test/test_YoutubeDL.py b/test/test_YoutubeDL.py index ab61e1976..678b9f7d1 100644 --- a/test/test_YoutubeDL.py +++ b/test/test_YoutubeDL.py @@ -8,6 +8,8 @@ import sys  import unittest  sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +import copy +  from test.helper import FakeYDL, assertRegexpMatches  from youtube_dl import YoutubeDL  from youtube_dl.extractor import YoutubeIE @@ -192,6 +194,37 @@ class TestFormatSelection(unittest.TestCase):          downloaded = ydl.downloaded_info_dicts[0]          self.assertEqual(downloaded['format_id'], 'vid-high') +    def test_format_selection_audio_exts(self): +        formats = [ +            {'format_id': 'mp3-64', 'ext': 'mp3', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'}, +            {'format_id': 'ogg-64', 'ext': 'ogg', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'}, +            {'format_id': 'aac-64', 'ext': 'aac', 'abr': 64, 'url': 'http://_', 'vcodec': 'none'}, +            {'format_id': 'mp3-32', 'ext': 'mp3', 'abr': 32, 'url': 'http://_', 'vcodec': 'none'}, +            {'format_id': 'aac-32', 'ext': 'aac', 'abr': 32, 'url': 'http://_', 'vcodec': 'none'}, +        ] + +        info_dict = _make_result(formats) +        ydl = YDL({'format': 'best'}) +        ie = YoutubeIE(ydl) +        ie._sort_formats(info_dict['formats']) +        ydl.process_ie_result(copy.deepcopy(info_dict)) +        downloaded = ydl.downloaded_info_dicts[0] +        self.assertEqual(downloaded['format_id'], 'aac-64') + +        ydl = YDL({'format': 'mp3'}) +        ie = YoutubeIE(ydl) +        ie._sort_formats(info_dict['formats']) +        ydl.process_ie_result(copy.deepcopy(info_dict)) +        downloaded = ydl.downloaded_info_dicts[0] +        self.assertEqual(downloaded['format_id'], 'mp3-64') + +        ydl = YDL({'prefer_free_formats': True}) +        ie = YoutubeIE(ydl) +        ie._sort_formats(info_dict['formats']) +        ydl.process_ie_result(copy.deepcopy(info_dict)) +        downloaded = ydl.downloaded_info_dicts[0] +        self.assertEqual(downloaded['format_id'], 'ogg-64') +      def test_format_selection_video(self):          formats = [              {'format_id': 'dash-video-low', 'ext': 'mp4', 'preference': 1, 'acodec': 'none', 'url': '_'}, @@ -218,7 +251,7 @@ class TestFormatSelection(unittest.TestCase):              # 3D              '85', '84', '102', '83', '101', '82', '100',              # Dash video -            '138', '137', '248', '136', '247', '135', '246', +            '137', '248', '136', '247', '135', '246',              '245', '244', '134', '243', '133', '242', '160',              # Dash audio              '141', '172', '140', '171', '139', @@ -248,6 +281,61 @@ class TestFormatSelection(unittest.TestCase):              downloaded = ydl.downloaded_info_dicts[0]              self.assertEqual(downloaded['format_id'], f1id) +    def test_format_filtering(self): +        formats = [ +            {'format_id': 'A', 'filesize': 500, 'width': 1000}, +            {'format_id': 'B', 'filesize': 1000, 'width': 500}, +            {'format_id': 'C', 'filesize': 1000, 'width': 400}, +            {'format_id': 'D', 'filesize': 2000, 'width': 600}, +            {'format_id': 'E', 'filesize': 3000}, +            {'format_id': 'F'}, +            {'format_id': 'G', 'filesize': 1000000}, +        ] +        for f in formats: +            f['url'] = 'http://_/' +            f['ext'] = 'unknown' +        info_dict = _make_result(formats) + +        ydl = YDL({'format': 'best[filesize<3000]'}) +        ydl.process_ie_result(info_dict) +        downloaded = ydl.downloaded_info_dicts[0] +        self.assertEqual(downloaded['format_id'], 'D') + +        ydl = YDL({'format': 'best[filesize<=3000]'}) +        ydl.process_ie_result(info_dict) +        downloaded = ydl.downloaded_info_dicts[0] +        self.assertEqual(downloaded['format_id'], 'E') + +        ydl = YDL({'format': 'best[filesize <= ? 3000]'}) +        ydl.process_ie_result(info_dict) +        downloaded = ydl.downloaded_info_dicts[0] +        self.assertEqual(downloaded['format_id'], 'F') + +        ydl = YDL({'format': 'best [filesize = 1000] [width>450]'}) +        ydl.process_ie_result(info_dict) +        downloaded = ydl.downloaded_info_dicts[0] +        self.assertEqual(downloaded['format_id'], 'B') + +        ydl = YDL({'format': 'best [filesize = 1000] [width!=450]'}) +        ydl.process_ie_result(info_dict) +        downloaded = ydl.downloaded_info_dicts[0] +        self.assertEqual(downloaded['format_id'], 'C') + +        ydl = YDL({'format': '[filesize>?1]'}) +        ydl.process_ie_result(info_dict) +        downloaded = ydl.downloaded_info_dicts[0] +        self.assertEqual(downloaded['format_id'], 'G') + +        ydl = YDL({'format': '[filesize<1M]'}) +        ydl.process_ie_result(info_dict) +        downloaded = ydl.downloaded_info_dicts[0] +        self.assertEqual(downloaded['format_id'], 'E') + +        ydl = YDL({'format': '[filesize<1MiB]'}) +        ydl.process_ie_result(info_dict) +        downloaded = ydl.downloaded_info_dicts[0] +        self.assertEqual(downloaded['format_id'], 'G') +      def test_add_extra_info(self):          test_dict = {              'extractor': 'Foo', @@ -266,6 +354,7 @@ class TestFormatSelection(unittest.TestCase):              'ext': 'mp4',              'width': None,          } +          def fname(templ):              ydl = YoutubeDL({'outtmpl': templ})              return ydl.prepare_filename(info) diff --git a/test/test_age_restriction.py b/test/test_age_restriction.py index 71e80b037..6f5513faa 100644 --- a/test/test_age_restriction.py +++ b/test/test_age_restriction.py @@ -1,4 +1,5 @@  #!/usr/bin/env python +from __future__ import unicode_literals  # Allow direct execution  import os @@ -19,7 +20,7 @@ def _download_restricted(url, filename, age):          'age_limit': age,          'skip_download': True,          'writeinfojson': True, -        "outtmpl": "%(id)s.%(ext)s", +        'outtmpl': '%(id)s.%(ext)s',      }      ydl = YoutubeDL(params)      ydl.add_default_info_extractors() @@ -44,11 +45,6 @@ class TestAgeRestriction(unittest.TestCase):              'http://www.youporn.com/watch/505835/sex-ed-is-it-safe-to-masturbate-daily/',              '505835.mp4', 2, old_age=25) -    def test_pornotube(self): -        self._assert_restricted( -            'http://pornotube.com/c/173/m/1689755/Marilyn-Monroe-Bathing', -            '1689755.flv', 13) -  if __name__ == '__main__':      unittest.main() diff --git a/test/test_all_urls.py b/test/test_all_urls.py index 965e5d8a5..e66264b4b 100644 --- a/test/test_all_urls.py +++ b/test/test_all_urls.py @@ -14,7 +14,6 @@ from test.helper import gettestcases  from youtube_dl.extractor import (      FacebookIE,      gen_extractors, -    TwitchIE,      YoutubeIE,  ) @@ -32,19 +31,19 @@ class TestAllURLsMatching(unittest.TestCase):      def test_youtube_playlist_matching(self):          assertPlaylist = lambda url: self.assertMatch(url, ['youtube:playlist'])          assertPlaylist('ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8') -        assertPlaylist('UUBABnxM4Ar9ten8Mdjj1j0Q') #585 +        assertPlaylist('UUBABnxM4Ar9ten8Mdjj1j0Q')  # 585          assertPlaylist('PL63F0C78739B09958')          assertPlaylist('https://www.youtube.com/playlist?list=UUBABnxM4Ar9ten8Mdjj1j0Q')          assertPlaylist('https://www.youtube.com/course?list=ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')          assertPlaylist('https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC') -        assertPlaylist('https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012') #668 +        assertPlaylist('https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012')  # 668          self.assertFalse('youtube:playlist' in self.matching_ies('PLtS2H6bU1M'))          # Top tracks          assertPlaylist('https://www.youtube.com/playlist?list=MCUS.20142101')      def test_youtube_matching(self):          self.assertTrue(YoutubeIE.suitable('PLtS2H6bU1M')) -        self.assertFalse(YoutubeIE.suitable('https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012')) #668 +        self.assertFalse(YoutubeIE.suitable('https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012'))  # 668          self.assertMatch('http://youtu.be/BaW_jenozKc', ['youtube'])          self.assertMatch('http://www.youtube.com/v/BaW_jenozKc', ['youtube'])          self.assertMatch('https://youtube.googleapis.com/v/BaW_jenozKc', ['youtube']) @@ -72,18 +71,6 @@ class TestAllURLsMatching(unittest.TestCase):          self.assertMatch('http://www.youtube.com/results?search_query=making+mustard', ['youtube:search_url'])          self.assertMatch('https://www.youtube.com/results?baz=bar&search_query=youtube-dl+test+video&filters=video&lclk=video', ['youtube:search_url']) -    def test_twitch_channelid_matching(self): -        self.assertTrue(TwitchIE.suitable('twitch.tv/vanillatv')) -        self.assertTrue(TwitchIE.suitable('www.twitch.tv/vanillatv')) -        self.assertTrue(TwitchIE.suitable('http://www.twitch.tv/vanillatv')) -        self.assertTrue(TwitchIE.suitable('http://www.twitch.tv/vanillatv/')) - -    def test_twitch_videoid_matching(self): -        self.assertTrue(TwitchIE.suitable('http://www.twitch.tv/vanillatv/b/328087483')) - -    def test_twitch_chapterid_matching(self): -        self.assertTrue(TwitchIE.suitable('http://www.twitch.tv/tsm_theoddone/c/2349361')) -      def test_youtube_extract(self):          assertExtractId = lambda url, id: self.assertEqual(YoutubeIE.extract_id(url), id)          assertExtractId('http://www.youtube.com/watch?&v=BaW_jenozKc', 'BaW_jenozKc') @@ -115,8 +102,6 @@ class TestAllURLsMatching(unittest.TestCase):          self.assertMatch(':ythistory', ['youtube:history'])          self.assertMatch(':thedailyshow', ['ComedyCentralShows'])          self.assertMatch(':tds', ['ComedyCentralShows']) -        self.assertMatch(':colbertreport', ['ComedyCentralShows']) -        self.assertMatch(':cr', ['ComedyCentralShows'])      def test_vimeo_matching(self):          self.assertMatch('http://vimeo.com/channels/tributes', ['vimeo:channel']) diff --git a/test/test_compat.py b/test/test_compat.py new file mode 100644 index 000000000..1eb454e06 --- /dev/null +++ b/test/test_compat.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# coding: utf-8 + +from __future__ import unicode_literals + +# Allow direct execution +import os +import sys +import unittest +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + + +from youtube_dl.utils import get_filesystem_encoding +from youtube_dl.compat import ( +    compat_getenv, +    compat_expanduser, +) + + +class TestCompat(unittest.TestCase): +    def test_compat_getenv(self): +        test_str = 'тест' +        os.environ['YOUTUBE-DL-TEST'] = ( +            test_str if sys.version_info >= (3, 0) +            else test_str.encode(get_filesystem_encoding())) +        self.assertEqual(compat_getenv('YOUTUBE-DL-TEST'), test_str) + +    def test_compat_expanduser(self): +        old_home = os.environ.get('HOME') +        test_str = 'C:\Documents and Settings\тест\Application Data' +        os.environ['HOME'] = ( +            test_str if sys.version_info >= (3, 0) +            else test_str.encode(get_filesystem_encoding())) +        self.assertEqual(compat_expanduser('~'), test_str) +        os.environ['HOME'] = old_home + +    def test_all_present(self): +        import youtube_dl.compat +        all_names = youtube_dl.compat.__all__ +        present_names = set(filter( +            lambda c: '_' in c and not c.startswith('_'), +            dir(youtube_dl.compat))) - set(['unicode_literals']) +        self.assertEqual(all_names, sorted(present_names)) + +if __name__ == '__main__': +    unittest.main() diff --git a/test/test_download.py b/test/test_download.py index 8178015ea..412f3dbce 100644 --- a/test/test_download.py +++ b/test/test_download.py @@ -1,5 +1,7 @@  #!/usr/bin/env python +from __future__ import unicode_literals +  # Allow direct execution  import os  import sys @@ -8,6 +10,7 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))  from test.helper import (      assertGreaterEqual, +    expect_warnings,      get_params,      gettestcases,      expect_info_dict, @@ -22,10 +25,12 @@ import json  import socket  import youtube_dl.YoutubeDL -from youtube_dl.utils import ( +from youtube_dl.compat import (      compat_http_client,      compat_urllib_error,      compat_HTTPError, +) +from youtube_dl.utils import (      DownloadError,      ExtractorError,      format_bytes, @@ -35,18 +40,22 @@ from youtube_dl.extractor import get_info_extractor  RETRIES = 3 +  class YoutubeDL(youtube_dl.YoutubeDL):      def __init__(self, *args, **kwargs):          self.to_stderr = self.to_screen          self.processed_info_dicts = []          super(YoutubeDL, self).__init__(*args, **kwargs) +      def report_warning(self, message):          # Don't accept warnings during tests          raise ExtractorError(message) +      def process_info(self, info_dict):          self.processed_info_dicts.append(info_dict)          return super(YoutubeDL, self).process_info(info_dict) +  def _file_md5(fn):      with open(fn, 'rb') as f:          return hashlib.md5(f.read()).hexdigest() @@ -56,10 +65,13 @@ defs = gettestcases()  class TestDownload(unittest.TestCase):      maxDiff = None +      def setUp(self):          self.defs = defs -### Dynamically generate tests +# Dynamically generate tests + +  def generator(test_case):      def test_template(self): @@ -85,7 +97,7 @@ def generator(test_case):              return          for other_ie in other_ies:              if not other_ie.working(): -                print_skipping(u'test depends on %sIE, marked as not WORKING' % other_ie.ie_key()) +                print_skipping('test depends on %sIE, marked as not WORKING' % other_ie.ie_key())                  return          params = get_params(test_case.get('params', {})) @@ -93,18 +105,21 @@ def generator(test_case):              params.setdefault('extract_flat', True)              params.setdefault('skip_download', True) -        ydl = YoutubeDL(params) +        ydl = YoutubeDL(params, auto_init=False)          ydl.add_default_info_extractors()          finished_hook_called = set() +          def _hook(status):              if status['status'] == 'finished':                  finished_hook_called.add(status['filename'])          ydl.add_progress_hook(_hook) +        expect_warnings(ydl, test_case.get('expected_warnings', []))          def get_tc_filename(tc):              return tc.get('file') or ydl.prepare_filename(tc.get('info_dict', {}))          res_dict = None +          def try_rm_tcs_files(tcs=None):              if tcs is None:                  tcs = test_cases @@ -128,7 +143,7 @@ def generator(test_case):                          raise                      if try_num == RETRIES: -                        report_warning(u'Failed due to network errors, skipping...') +                        report_warning('Failed due to network errors, skipping...')                          return                      print('Retrying: {0} failed tries\n\n##########\n\n'.format(try_num)) @@ -140,7 +155,7 @@ def generator(test_case):              if is_playlist:                  self.assertEqual(res_dict['_type'], 'playlist')                  self.assertTrue('entries' in res_dict) -                expect_info_dict(self, test_case.get('info_dict', {}), res_dict) +                expect_info_dict(self, res_dict, test_case.get('info_dict', {}))              if 'playlist_mincount' in test_case:                  assertGreaterEqual( @@ -183,11 +198,13 @@ def generator(test_case):                          md5_for_file = _file_md5(tc_filename)                          self.assertEqual(md5_for_file, tc['md5'])                  info_json_fn = os.path.splitext(tc_filename)[0] + '.info.json' -                self.assertTrue(os.path.exists(info_json_fn)) +                self.assertTrue( +                    os.path.exists(info_json_fn), +                    'Missing info file %s' % info_json_fn)                  with io.open(info_json_fn, encoding='utf-8') as infof:                      info_dict = json.load(infof) -                expect_info_dict(self, tc.get('info_dict', {}), info_dict) +                expect_info_dict(self, info_dict, tc.get('info_dict', {}))          finally:              try_rm_tcs_files()              if is_playlist and res_dict is not None and res_dict.get('entries'): @@ -198,15 +215,15 @@ def generator(test_case):      return test_template -### And add them to TestDownload +# And add them to TestDownload  for n, test_case in enumerate(defs):      test_method = generator(test_case)      tname = 'test_' + str(test_case['name'])      i = 1      while hasattr(TestDownload, tname): -        tname = 'test_'  + str(test_case['name']) + '_' + str(i) +        tname = 'test_%s_%d' % (test_case['name'], i)          i += 1 -    test_method.__name__ = tname +    test_method.__name__ = str(tname)      setattr(TestDownload, test_method.__name__, test_method)      del test_method diff --git a/test/test_execution.py b/test/test_execution.py index 2b115fb31..60df187de 100644 --- a/test/test_execution.py +++ b/test/test_execution.py @@ -1,3 +1,6 @@ +#!/usr/bin/env python +from __future__ import unicode_literals +  import unittest  import sys @@ -6,17 +9,19 @@ import subprocess  rootDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +  try:      _DEV_NULL = subprocess.DEVNULL  except AttributeError:      _DEV_NULL = open(os.devnull, 'wb') +  class TestExecution(unittest.TestCase):      def test_import(self):          subprocess.check_call([sys.executable, '-c', 'import youtube_dl'], cwd=rootDir)      def test_module_exec(self): -        if sys.version_info >= (2,7): # Python 2.6 doesn't support package execution +        if sys.version_info >= (2, 7):  # Python 2.6 doesn't support package execution              subprocess.check_call([sys.executable, '-m', 'youtube_dl', '--version'], cwd=rootDir, stdout=_DEV_NULL)      def test_main_exec(self): diff --git a/test/test_subtitles.py b/test/test_subtitles.py index 8f4602e5f..6336dd317 100644 --- a/test/test_subtitles.py +++ b/test/test_subtitles.py @@ -1,4 +1,5 @@  #!/usr/bin/env python +from __future__ import unicode_literals  # Allow direct execution  import os @@ -16,12 +17,14 @@ from youtube_dl.extractor import (      TEDIE,      VimeoIE,      WallaIE, +    CeskaTelevizeIE,  )  class BaseTestSubtitles(unittest.TestCase):      url = None      IE = None +      def setUp(self):          self.DL = FakeYDL()          self.ie = self.IE(self.DL) @@ -74,7 +77,7 @@ class TestYoutubeSubtitles(BaseTestSubtitles):          self.assertEqual(md5(subtitles['en']), '3cb210999d3e021bd6c7f0ea751eab06')      def test_youtube_list_subtitles(self): -        self.DL.expect_warning(u'Video doesn\'t have automatic captions') +        self.DL.expect_warning('Video doesn\'t have automatic captions')          self.DL.params['listsubtitles'] = True          info_dict = self.getInfoDict()          self.assertEqual(info_dict, None) @@ -86,8 +89,16 @@ class TestYoutubeSubtitles(BaseTestSubtitles):          subtitles = self.getSubtitles()          self.assertTrue(subtitles['it'] is not None) +    def test_youtube_translated_subtitles(self): +        # This video has a subtitles track, which can be translated +        self.url = 'Ky9eprVWzlI' +        self.DL.params['writeautomaticsub'] = True +        self.DL.params['subtitleslangs'] = ['it'] +        subtitles = self.getSubtitles() +        self.assertTrue(subtitles['it'] is not None) +      def test_youtube_nosubtitles(self): -        self.DL.expect_warning(u'video doesn\'t have subtitles') +        self.DL.expect_warning('video doesn\'t have subtitles')          self.url = 'n5BB19UTcdA'          self.DL.params['writesubtitles'] = True          self.DL.params['allsubtitles'] = True @@ -101,7 +112,7 @@ class TestYoutubeSubtitles(BaseTestSubtitles):          self.DL.params['subtitleslangs'] = langs          subtitles = self.getSubtitles()          for lang in langs: -            self.assertTrue(subtitles.get(lang) is not None, u'Subtitles for \'%s\' not extracted' % lang) +            self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)  class TestDailymotionSubtitles(BaseTestSubtitles): @@ -130,20 +141,20 @@ class TestDailymotionSubtitles(BaseTestSubtitles):          self.assertEqual(len(subtitles.keys()), 5)      def test_list_subtitles(self): -        self.DL.expect_warning(u'Automatic Captions not supported by this server') +        self.DL.expect_warning('Automatic Captions not supported by this server')          self.DL.params['listsubtitles'] = True          info_dict = self.getInfoDict()          self.assertEqual(info_dict, None)      def test_automatic_captions(self): -        self.DL.expect_warning(u'Automatic Captions not supported by this server') +        self.DL.expect_warning('Automatic Captions not supported by this server')          self.DL.params['writeautomaticsub'] = True          self.DL.params['subtitleslang'] = ['en']          subtitles = self.getSubtitles()          self.assertTrue(len(subtitles.keys()) == 0)      def test_nosubtitles(self): -        self.DL.expect_warning(u'video doesn\'t have subtitles') +        self.DL.expect_warning('video doesn\'t have subtitles')          self.url = 'http://www.dailymotion.com/video/x12u166_le-zapping-tele-star-du-08-aout-2013_tv'          self.DL.params['writesubtitles'] = True          self.DL.params['allsubtitles'] = True @@ -156,7 +167,7 @@ class TestDailymotionSubtitles(BaseTestSubtitles):          self.DL.params['subtitleslangs'] = langs          subtitles = self.getSubtitles()          for lang in langs: -            self.assertTrue(subtitles.get(lang) is not None, u'Subtitles for \'%s\' not extracted' % lang) +            self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)  class TestTedSubtitles(BaseTestSubtitles): @@ -185,13 +196,13 @@ class TestTedSubtitles(BaseTestSubtitles):          self.assertTrue(len(subtitles.keys()) >= 28)      def test_list_subtitles(self): -        self.DL.expect_warning(u'Automatic Captions not supported by this server') +        self.DL.expect_warning('Automatic Captions not supported by this server')          self.DL.params['listsubtitles'] = True          info_dict = self.getInfoDict()          self.assertEqual(info_dict, None)      def test_automatic_captions(self): -        self.DL.expect_warning(u'Automatic Captions not supported by this server') +        self.DL.expect_warning('Automatic Captions not supported by this server')          self.DL.params['writeautomaticsub'] = True          self.DL.params['subtitleslang'] = ['en']          subtitles = self.getSubtitles() @@ -203,7 +214,7 @@ class TestTedSubtitles(BaseTestSubtitles):          self.DL.params['subtitleslangs'] = langs          subtitles = self.getSubtitles()          for lang in langs: -            self.assertTrue(subtitles.get(lang) is not None, u'Subtitles for \'%s\' not extracted' % lang) +            self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)  class TestBlipTVSubtitles(BaseTestSubtitles): @@ -211,13 +222,13 @@ class TestBlipTVSubtitles(BaseTestSubtitles):      IE = BlipTVIE      def test_list_subtitles(self): -        self.DL.expect_warning(u'Automatic Captions not supported by this server') +        self.DL.expect_warning('Automatic Captions not supported by this server')          self.DL.params['listsubtitles'] = True          info_dict = self.getInfoDict()          self.assertEqual(info_dict, None)      def test_allsubtitles(self): -        self.DL.expect_warning(u'Automatic Captions not supported by this server') +        self.DL.expect_warning('Automatic Captions not supported by this server')          self.DL.params['writesubtitles'] = True          self.DL.params['allsubtitles'] = True          subtitles = self.getSubtitles() @@ -236,7 +247,7 @@ class TestVimeoSubtitles(BaseTestSubtitles):      def test_subtitles(self):          self.DL.params['writesubtitles'] = True          subtitles = self.getSubtitles() -        self.assertEqual(md5(subtitles['en']), '8062383cf4dec168fc40a088aa6d5888') +        self.assertEqual(md5(subtitles['en']), '26399116d23ae3cf2c087cea94bc43b4')      def test_subtitles_lang(self):          self.DL.params['writesubtitles'] = True @@ -251,20 +262,20 @@ class TestVimeoSubtitles(BaseTestSubtitles):          self.assertEqual(set(subtitles.keys()), set(['de', 'en', 'es', 'fr']))      def test_list_subtitles(self): -        self.DL.expect_warning(u'Automatic Captions not supported by this server') +        self.DL.expect_warning('Automatic Captions not supported by this server')          self.DL.params['listsubtitles'] = True          info_dict = self.getInfoDict()          self.assertEqual(info_dict, None)      def test_automatic_captions(self): -        self.DL.expect_warning(u'Automatic Captions not supported by this server') +        self.DL.expect_warning('Automatic Captions not supported by this server')          self.DL.params['writeautomaticsub'] = True          self.DL.params['subtitleslang'] = ['en']          subtitles = self.getSubtitles()          self.assertTrue(len(subtitles.keys()) == 0)      def test_nosubtitles(self): -        self.DL.expect_warning(u'video doesn\'t have subtitles') +        self.DL.expect_warning('video doesn\'t have subtitles')          self.url = 'http://vimeo.com/56015672'          self.DL.params['writesubtitles'] = True          self.DL.params['allsubtitles'] = True @@ -277,7 +288,7 @@ class TestVimeoSubtitles(BaseTestSubtitles):          self.DL.params['subtitleslangs'] = langs          subtitles = self.getSubtitles()          for lang in langs: -            self.assertTrue(subtitles.get(lang) is not None, u'Subtitles for \'%s\' not extracted' % lang) +            self.assertTrue(subtitles.get(lang) is not None, 'Subtitles for \'%s\' not extracted' % lang)  class TestWallaSubtitles(BaseTestSubtitles): @@ -285,13 +296,13 @@ class TestWallaSubtitles(BaseTestSubtitles):      IE = WallaIE      def test_list_subtitles(self): -        self.DL.expect_warning(u'Automatic Captions not supported by this server') +        self.DL.expect_warning('Automatic Captions not supported by this server')          self.DL.params['listsubtitles'] = True          info_dict = self.getInfoDict()          self.assertEqual(info_dict, None)      def test_allsubtitles(self): -        self.DL.expect_warning(u'Automatic Captions not supported by this server') +        self.DL.expect_warning('Automatic Captions not supported by this server')          self.DL.params['writesubtitles'] = True          self.DL.params['allsubtitles'] = True          subtitles = self.getSubtitles() @@ -299,7 +310,7 @@ class TestWallaSubtitles(BaseTestSubtitles):          self.assertEqual(md5(subtitles['heb']), 'e758c5d7cb982f6bef14f377ec7a3920')      def test_nosubtitles(self): -        self.DL.expect_warning(u'video doesn\'t have subtitles') +        self.DL.expect_warning('video doesn\'t have subtitles')          self.url = 'http://vod.walla.co.il/movie/2642630/one-direction-all-for-one'          self.DL.params['writesubtitles'] = True          self.DL.params['allsubtitles'] = True @@ -307,5 +318,32 @@ class TestWallaSubtitles(BaseTestSubtitles):          self.assertEqual(len(subtitles), 0) +class TestCeskaTelevizeSubtitles(BaseTestSubtitles): +    url = 'http://www.ceskatelevize.cz/ivysilani/10600540290-u6-uzasny-svet-techniky' +    IE = CeskaTelevizeIE + +    def test_list_subtitles(self): +        self.DL.expect_warning('Automatic Captions not supported by this server') +        self.DL.params['listsubtitles'] = True +        info_dict = self.getInfoDict() +        self.assertEqual(info_dict, None) + +    def test_allsubtitles(self): +        self.DL.expect_warning('Automatic Captions not supported by this server') +        self.DL.params['writesubtitles'] = True +        self.DL.params['allsubtitles'] = True +        subtitles = self.getSubtitles() +        self.assertEqual(set(subtitles.keys()), set(['cs'])) +        self.assertEqual(md5(subtitles['cs']), '9bf52d9549533c32c427e264bf0847d4') + +    def test_nosubtitles(self): +        self.DL.expect_warning('video doesn\'t have subtitles') +        self.url = 'http://www.ceskatelevize.cz/ivysilani/ivysilani/10441294653-hyde-park-civilizace/214411058091220' +        self.DL.params['writesubtitles'] = True +        self.DL.params['allsubtitles'] = True +        subtitles = self.getSubtitles() +        self.assertEqual(len(subtitles), 0) + +  if __name__ == '__main__':      unittest.main() diff --git a/test/test_swfinterp.py b/test/test_swfinterp.py index b42cd74c7..9f18055e6 100644 --- a/test/test_swfinterp.py +++ b/test/test_swfinterp.py @@ -1,4 +1,5 @@  #!/usr/bin/env python +from __future__ import unicode_literals  # Allow direct execution  import os @@ -37,7 +38,9 @@ def _make_testfunc(testfile):                  or os.path.getmtime(swf_file) < os.path.getmtime(as_file)):              # Recompile              try: -                subprocess.check_call(['mxmlc', '-output', swf_file, as_file]) +                subprocess.check_call([ +                    'mxmlc', '-output', swf_file, +                    '-static-link-runtime-shared-libraries', as_file])              except OSError as ose:                  if ose.errno == errno.ENOENT:                      print('mxmlc not found! Skipping test.') diff --git a/test/test_unicode_literals.py b/test/test_unicode_literals.py index a4ba7bad0..7f816698e 100644 --- a/test/test_unicode_literals.py +++ b/test/test_unicode_literals.py @@ -1,22 +1,28 @@  from __future__ import unicode_literals -import io +# Allow direct execution  import os -import re +import sys  import unittest +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +import io +import re  rootDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  IGNORED_FILES = [      'setup.py',  # http://bugs.python.org/issue13943 +    'conf.py', +    'buildserver.py',  ] +from test.helper import assertRegexpMatches + +  class TestUnicodeLiterals(unittest.TestCase):      def test_all_files(self): -        print('Skipping this test (not yet fully implemented)') -        return -          for dirpath, _, filenames in os.walk(rootDir):              for basename in filenames:                  if not basename.endswith('.py'): @@ -30,10 +36,11 @@ class TestUnicodeLiterals(unittest.TestCase):                  if "'" not in code and '"' not in code:                      continue -                imps = 'from __future__ import unicode_literals' -                self.assertTrue( -                    imps in code, -                    ' %s  missing in %s' % (imps, fn)) +                assertRegexpMatches( +                    self, +                    code, +                    r'(?:(?:#.*?|\s*)\n)*from __future__ import (?:[a-z_]+,\s*)*unicode_literals', +                    'unicode_literals import  missing in %s' % fn)                  m = re.search(r'(?<=\s)u[\'"](?!\)|,|$)', code)                  if m is not None: diff --git a/test/test_utils.py b/test/test_utils.py index bcca0efea..ebec7986f 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -16,35 +16,43 @@ import json  import xml.etree.ElementTree  from youtube_dl.utils import ( +    age_restricted, +    args_to_str, +    clean_html,      DateRange, +    detect_exe_version,      encodeFilename, +    escape_rfc3986, +    escape_url,      find_xpath_attr,      fix_xml_ampersands, -    get_meta_content, -    orderedSet, -    OnDemandPagedList,      InAdvancePagedList, +    intlist_to_bytes, +    is_html, +    js_to_json, +    limit_length, +    OnDemandPagedList, +    orderedSet,      parse_duration, +    parse_filesize, +    parse_iso8601,      read_batch_urls,      sanitize_filename,      shell_quote,      smuggle_url,      str_to_int, +    strip_jsonp,      struct_unpack,      timeconvert,      unescapeHTML,      unified_strdate,      unsmuggle_url, +    uppercase_escape,      url_basename,      urlencode_postdata, +    version_tuple,      xpath_with_ns, -    parse_iso8601, -    strip_jsonp, -    uppercase_escape, -    limit_length, -    escape_rfc3986, -    escape_url, -    js_to_json, +    render_table,  ) @@ -73,6 +81,10 @@ class TestUtil(unittest.TestCase):          tests = '\u043a\u0438\u0440\u0438\u043b\u043b\u0438\u0446\u0430'          self.assertEqual(sanitize_filename(tests), tests) +        self.assertEqual( +            sanitize_filename('New World record at 0:12:34'), +            'New World record at 0_12_34') +          forbidden = '"\0\\/'          for fc in forbidden:              for fbc in forbidden: @@ -117,16 +129,16 @@ class TestUtil(unittest.TestCase):          self.assertEqual(orderedSet([1, 1, 2, 3, 4, 4, 5, 6, 7, 3, 5]), [1, 2, 3, 4, 5, 6, 7])          self.assertEqual(orderedSet([]), [])          self.assertEqual(orderedSet([1]), [1]) -        #keep the list ordered +        # keep the list ordered          self.assertEqual(orderedSet([135, 1, 1, 1]), [135, 1])      def test_unescape_html(self):          self.assertEqual(unescapeHTML('%20;'), '%20;')          self.assertEqual(              unescapeHTML('é'), 'é') -         +      def test_daterange(self): -        _20century = DateRange("19000101","20000101") +        _20century = DateRange("19000101", "20000101")          self.assertFalse("17890714" in _20century)          _ac = DateRange("00010101")          self.assertTrue("19690721" in _ac) @@ -138,8 +150,12 @@ class TestUtil(unittest.TestCase):          self.assertEqual(unified_strdate('8/7/2009'), '20090708')          self.assertEqual(unified_strdate('Dec 14, 2012'), '20121214')          self.assertEqual(unified_strdate('2012/10/11 01:56:38 +0000'), '20121011') +        self.assertEqual(unified_strdate('1968 12 10'), '19681210')          self.assertEqual(unified_strdate('1968-12-10'), '19681210')          self.assertEqual(unified_strdate('28/01/2014 21:00:00 +0100'), '20140128') +        self.assertEqual( +            unified_strdate('11/26/2014 11:30:00 AM PST', day_first=False), +            '20141126')      def test_find_xpath_attr(self):          testxml = '''<root> @@ -154,17 +170,6 @@ class TestUtil(unittest.TestCase):          self.assertEqual(find_xpath_attr(doc, './/node', 'x', 'a'), doc[1])          self.assertEqual(find_xpath_attr(doc, './/node', 'y', 'c'), doc[2]) -    def test_meta_parser(self): -        testhtml = ''' -        <head> -            <meta name="description" content="foo & bar"> -            <meta content='Plato' name='author'/> -        </head> -        ''' -        get_meta = lambda name: get_meta_content(name, testhtml) -        self.assertEqual(get_meta('description'), 'foo & bar') -        self.assertEqual(get_meta('author'), 'Plato') -      def test_xpath_with_ns(self):          testxml = '''<root xmlns:media="http://example.com/">              <media:song> @@ -179,7 +184,7 @@ class TestUtil(unittest.TestCase):          self.assertEqual(find('media:song/url').text, 'http://server.com/download.mp3')      def test_smuggle_url(self): -        data = {u"ö": u"ö", u"abc": [3]} +        data = {"ö": "ö", "abc": [3]}          url = 'https://foo.bar/baz?x=y#a'          smug_url = smuggle_url(url, data)          unsmug_url, unsmug_data = unsmuggle_url(smug_url) @@ -210,6 +215,8 @@ class TestUtil(unittest.TestCase):      def test_parse_duration(self):          self.assertEqual(parse_duration(None), None) +        self.assertEqual(parse_duration(False), None) +        self.assertEqual(parse_duration('invalid'), None)          self.assertEqual(parse_duration('1'), 1)          self.assertEqual(parse_duration('1337:12'), 80232)          self.assertEqual(parse_duration('9:12:43'), 33163) @@ -227,6 +234,10 @@ class TestUtil(unittest.TestCase):          self.assertEqual(parse_duration('0m0s'), 0)          self.assertEqual(parse_duration('0s'), 0)          self.assertEqual(parse_duration('01:02:03.05'), 3723.05) +        self.assertEqual(parse_duration('T30M38S'), 1838) +        self.assertEqual(parse_duration('5 s'), 5) +        self.assertEqual(parse_duration('3 min'), 180) +        self.assertEqual(parse_duration('2.5 hours'), 9000)      def test_fix_xml_ampersands(self):          self.assertEqual( @@ -286,12 +297,17 @@ class TestUtil(unittest.TestCase):          self.assertEqual(parse_iso8601('2014-03-23T23:04:26+0100'), 1395612266)          self.assertEqual(parse_iso8601('2014-03-23T22:04:26+0000'), 1395612266)          self.assertEqual(parse_iso8601('2014-03-23T22:04:26Z'), 1395612266) +        self.assertEqual(parse_iso8601('2014-03-23T22:04:26.1234Z'), 1395612266)      def test_strip_jsonp(self):          stripped = strip_jsonp('cb ([ {"id":"532cb",\n\n\n"x":\n3}\n]\n);')          d = json.loads(stripped)          self.assertEqual(d, [{"id": "532cb", "x": 3}]) +        stripped = strip_jsonp('parseMetadata({"STATUS":"OK"})\n\n\n//epc') +        d = json.loads(stripped) +        self.assertEqual(d, {'STATUS': 'OK'}) +      def test_uppercase_escape(self):          self.assertEqual(uppercase_escape('aä'), 'aä')          self.assertEqual(uppercase_escape('\\U0001d550'), '𝕐') @@ -355,5 +371,79 @@ class TestUtil(unittest.TestCase):          on = js_to_json('{"abc": true}')          self.assertEqual(json.loads(on), {'abc': True}) +    def test_clean_html(self): +        self.assertEqual(clean_html('a:\nb'), 'a: b') +        self.assertEqual(clean_html('a:\n   "b"'), 'a:    "b"') + +    def test_intlist_to_bytes(self): +        self.assertEqual( +            intlist_to_bytes([0, 1, 127, 128, 255]), +            b'\x00\x01\x7f\x80\xff') + +    def test_args_to_str(self): +        self.assertEqual( +            args_to_str(['foo', 'ba/r', '-baz', '2 be', '']), +            'foo ba/r -baz \'2 be\' \'\'' +        ) + +    def test_parse_filesize(self): +        self.assertEqual(parse_filesize(None), None) +        self.assertEqual(parse_filesize(''), None) +        self.assertEqual(parse_filesize('91 B'), 91) +        self.assertEqual(parse_filesize('foobar'), None) +        self.assertEqual(parse_filesize('2 MiB'), 2097152) +        self.assertEqual(parse_filesize('5 GB'), 5000000000) +        self.assertEqual(parse_filesize('1.2Tb'), 1200000000000) +        self.assertEqual(parse_filesize('1,24 KB'), 1240) + +    def test_version_tuple(self): +        self.assertEqual(version_tuple('1'), (1,)) +        self.assertEqual(version_tuple('10.23.344'), (10, 23, 344)) +        self.assertEqual(version_tuple('10.1-6'), (10, 1, 6))  # avconv style + +    def test_detect_exe_version(self): +        self.assertEqual(detect_exe_version('''ffmpeg version 1.2.1 +built on May 27 2013 08:37:26 with gcc 4.7 (Debian 4.7.3-4) +configuration: --prefix=/usr --extra-'''), '1.2.1') +        self.assertEqual(detect_exe_version('''ffmpeg version N-63176-g1fb4685 +built on May 15 2014 22:09:06 with gcc 4.8.2 (GCC)'''), 'N-63176-g1fb4685') +        self.assertEqual(detect_exe_version('''X server found. dri2 connection failed! +Trying to open render node... +Success at /dev/dri/renderD128. +ffmpeg version 2.4.4 Copyright (c) 2000-2014 the FFmpeg ...'''), '2.4.4') + +    def test_age_restricted(self): +        self.assertFalse(age_restricted(None, 10))  # unrestricted content +        self.assertFalse(age_restricted(1, None))  # unrestricted policy +        self.assertFalse(age_restricted(8, 10)) +        self.assertTrue(age_restricted(18, 14)) +        self.assertFalse(age_restricted(18, 18)) + +    def test_is_html(self): +        self.assertFalse(is_html(b'\x49\x44\x43<html')) +        self.assertTrue(is_html(b'<!DOCTYPE foo>\xaaa')) +        self.assertTrue(is_html(  # UTF-8 with BOM +            b'\xef\xbb\xbf<!DOCTYPE foo>\xaaa')) +        self.assertTrue(is_html(  # UTF-16-LE +            b'\xff\xfe<\x00h\x00t\x00m\x00l\x00>\x00\xe4\x00' +        )) +        self.assertTrue(is_html(  # UTF-16-BE +            b'\xfe\xff\x00<\x00h\x00t\x00m\x00l\x00>\x00\xe4' +        )) +        self.assertTrue(is_html(  # UTF-32-BE +            b'\x00\x00\xFE\xFF\x00\x00\x00<\x00\x00\x00h\x00\x00\x00t\x00\x00\x00m\x00\x00\x00l\x00\x00\x00>\x00\x00\x00\xe4')) +        self.assertTrue(is_html(  # UTF-32-LE +            b'\xFF\xFE\x00\x00<\x00\x00\x00h\x00\x00\x00t\x00\x00\x00m\x00\x00\x00l\x00\x00\x00>\x00\x00\x00\xe4\x00\x00\x00')) + +    def test_render_table(self): +        self.assertEqual( +            render_table( +                ['a', 'bcd'], +                [[123, 4], [9999, 51]]), +            'a    bcd\n' +            '123  4\n' +            '9999 51') + +  if __name__ == '__main__':      unittest.main() diff --git a/test/test_write_annotations.py b/test/test_write_annotations.py index eac53b285..780636c77 100644 --- a/test/test_write_annotations.py +++ b/test/test_write_annotations.py @@ -1,5 +1,6 @@  #!/usr/bin/env python  # coding: utf-8 +from __future__ import unicode_literals  # Allow direct execution  import os @@ -31,19 +32,18 @@ params = get_params({  }) -  TEST_ID = 'gr51aVj-mLg'  ANNOTATIONS_FILE = TEST_ID + '.flv.annotations.xml'  EXPECTED_ANNOTATIONS = ['Speech bubble', 'Note', 'Title', 'Spotlight', 'Label'] +  class TestAnnotations(unittest.TestCase):      def setUp(self):          # Clear old files          self.tearDown() -      def test_info_json(self): -        expected = list(EXPECTED_ANNOTATIONS) #Two annotations could have the same text. +        expected = list(EXPECTED_ANNOTATIONS)  # Two annotations could have the same text.          ie = youtube_dl.extractor.YoutubeIE()          ydl = YoutubeDL(params)          ydl.add_info_extractor(ie) @@ -51,7 +51,7 @@ class TestAnnotations(unittest.TestCase):          self.assertTrue(os.path.exists(ANNOTATIONS_FILE))          annoxml = None          with io.open(ANNOTATIONS_FILE, 'r', encoding='utf-8') as annof: -                annoxml = xml.etree.ElementTree.parse(annof) +            annoxml = xml.etree.ElementTree.parse(annof)          self.assertTrue(annoxml is not None, 'Failed to parse annotations XML')          root = annoxml.getroot()          self.assertEqual(root.tag, 'document') @@ -59,18 +59,17 @@ class TestAnnotations(unittest.TestCase):          self.assertEqual(annotationsTag.tag, 'annotations')          annotations = annotationsTag.findall('annotation') -        #Not all the annotations have TEXT children and the annotations are returned unsorted. +        # Not all the annotations have TEXT children and the annotations are returned unsorted.          for a in annotations: -                self.assertEqual(a.tag, 'annotation') -                if a.get('type') == 'text': -                        textTag = a.find('TEXT') -                        text = textTag.text -                        self.assertTrue(text in expected) #assertIn only added in python 2.7 -                        #remove the first occurance, there could be more than one annotation with the same text -                        expected.remove(text) -        #We should have seen (and removed) all the expected annotation texts. +            self.assertEqual(a.tag, 'annotation') +            if a.get('type') == 'text': +                textTag = a.find('TEXT') +                text = textTag.text +                self.assertTrue(text in expected)  # assertIn only added in python 2.7 +                # remove the first occurance, there could be more than one annotation with the same text +                expected.remove(text) +        # We should have seen (and removed) all the expected annotation texts.          self.assertEqual(len(expected), 0, 'Not all expected annotations were found.') -              def tearDown(self):          try_rm(ANNOTATIONS_FILE) diff --git a/test/test_write_info_json.py b/test/test_write_info_json.py deleted file mode 100644 index 90426a559..000000000 --- a/test/test_write_info_json.py +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python -# coding: utf-8 - -# Allow direct execution -import os -import sys -import unittest -sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - -from test.helper import get_params - - -import io -import json - -import youtube_dl.YoutubeDL -import youtube_dl.extractor - - -class YoutubeDL(youtube_dl.YoutubeDL): -    def __init__(self, *args, **kwargs): -        super(YoutubeDL, self).__init__(*args, **kwargs) -        self.to_stderr = self.to_screen - -params = get_params({ -    'writeinfojson': True, -    'skip_download': True, -    'writedescription': True, -}) - - -TEST_ID = 'BaW_jenozKc' -INFO_JSON_FILE = TEST_ID + '.info.json' -DESCRIPTION_FILE = TEST_ID + '.mp4.description' -EXPECTED_DESCRIPTION = u'''test chars:  "'/\ä↭𝕐 -test URL: https://github.com/rg3/youtube-dl/issues/1892 - -This is a test video for youtube-dl. - -For more information, contact phihag@phihag.de .''' - - -class TestInfoJSON(unittest.TestCase): -    def setUp(self): -        # Clear old files -        self.tearDown() - -    def test_info_json(self): -        ie = youtube_dl.extractor.YoutubeIE() -        ydl = YoutubeDL(params) -        ydl.add_info_extractor(ie) -        ydl.download([TEST_ID]) -        self.assertTrue(os.path.exists(INFO_JSON_FILE)) -        with io.open(INFO_JSON_FILE, 'r', encoding='utf-8') as jsonf: -            jd = json.load(jsonf) -        self.assertEqual(jd['upload_date'], u'20121002') -        self.assertEqual(jd['description'], EXPECTED_DESCRIPTION) -        self.assertEqual(jd['id'], TEST_ID) -        self.assertEqual(jd['extractor'], 'youtube') -        self.assertEqual(jd['title'], u'''youtube-dl test video "'/\ä↭𝕐''') -        self.assertEqual(jd['uploader'], 'Philipp Hagemeister') - -        self.assertTrue(os.path.exists(DESCRIPTION_FILE)) -        with io.open(DESCRIPTION_FILE, 'r', encoding='utf-8') as descf: -            descr = descf.read() -        self.assertEqual(descr, EXPECTED_DESCRIPTION) - -    def tearDown(self): -        if os.path.exists(INFO_JSON_FILE): -            os.remove(INFO_JSON_FILE) -        if os.path.exists(DESCRIPTION_FILE): -            os.remove(DESCRIPTION_FILE) - -if __name__ == '__main__': -    unittest.main() diff --git a/test/test_youtube_lists.py b/test/test_youtube_lists.py index 410f9edc2..c889b6f15 100644 --- a/test/test_youtube_lists.py +++ b/test/test_youtube_lists.py @@ -1,4 +1,5 @@  #!/usr/bin/env python +from __future__ import unicode_literals  # Allow direct execution  import os @@ -12,10 +13,6 @@ from test.helper import FakeYDL  from youtube_dl.extractor import (      YoutubePlaylistIE,      YoutubeIE, -    YoutubeChannelIE, -    YoutubeShowIE, -    YoutubeTopListIE, -    YoutubeSearchURLIE,  ) @@ -31,7 +28,7 @@ class TestYoutubeLists(unittest.TestCase):          result = ie.extract('https://www.youtube.com/watch?v=FXxLjLQi3Fg&list=PLwiyx1dc3P2JR9N8gQaQN_BCvlSlap7re')          self.assertEqual(result['_type'], 'url')          self.assertEqual(YoutubeIE().extract_id(result['url']), 'FXxLjLQi3Fg') -     +      def test_youtube_course(self):          dl = FakeYDL()          ie = YoutubePlaylistIE(dl) diff --git a/test/test_youtube_signature.py b/test/test_youtube_signature.py index df2cb09f2..13d228cd8 100644 --- a/test/test_youtube_signature.py +++ b/test/test_youtube_signature.py @@ -14,7 +14,7 @@ import re  import string  from youtube_dl.extractor import YoutubeIE -from youtube_dl.utils import compat_str, compat_urlretrieve +from youtube_dl.compat import compat_str, compat_urlretrieve  _TESTS = [      ( | 
