diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/__init__.py | 0 | ||||
| -rw-r--r-- | test/helper.py | 66 | ||||
| -rw-r--r-- | test/parameters.json | 1 | ||||
| -rw-r--r-- | test/test_age_restriction.py | 55 | ||||
| -rw-r--r-- | test/test_all_urls.py | 89 | ||||
| -rw-r--r-- | test/test_dailymotion_subtitles.py | 70 | ||||
| -rw-r--r-- | test/test_download.py | 73 | ||||
| -rw-r--r-- | test/test_playlists.py | 89 | ||||
| -rw-r--r-- | test/test_utils.py | 54 | ||||
| -rw-r--r-- | test/test_write_annotations.py | 81 | ||||
| -rw-r--r-- | test/test_write_info_json.py | 32 | ||||
| -rw-r--r-- | test/test_youtube_lists.py | 30 | ||||
| -rwxr-xr-x | test/test_youtube_sig.py | 62 | ||||
| -rw-r--r-- | test/test_youtube_signature.py | 84 | ||||
| -rw-r--r-- | test/test_youtube_subtitles.py | 146 | 
15 files changed, 665 insertions, 267 deletions
diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/__init__.py diff --git a/test/helper.py b/test/helper.py index a2b468b50..79a0ede48 100644 --- a/test/helper.py +++ b/test/helper.py @@ -1,38 +1,63 @@ +import errno  import io +import hashlib  import json  import os.path +import re +import types  import youtube_dl.extractor -from youtube_dl import YoutubeDL, YoutubeDLHandler -from youtube_dl.utils import ( -    compat_cookiejar, -    compat_urllib_request, -) - -# General configuration (from __init__, not very elegant...) -jar = compat_cookiejar.CookieJar() -cookie_processor = compat_urllib_request.HTTPCookieProcessor(jar) -proxy_handler = compat_urllib_request.ProxyHandler() -opener = compat_urllib_request.build_opener(proxy_handler, cookie_processor, YoutubeDLHandler()) -compat_urllib_request.install_opener(opener) - -PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "parameters.json") -with io.open(PARAMETERS_FILE, encoding='utf-8') as pf: -    parameters = json.load(pf) +from youtube_dl import YoutubeDL + + +def global_setup(): +    youtube_dl._setup_opener(timeout=10) + + +def get_params(override=None): +    PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), +                                   "parameters.json") +    with io.open(PARAMETERS_FILE, encoding='utf-8') as pf: +        parameters = json.load(pf) +    if override: +        parameters.update(override) +    return parameters + + +def try_rm(filename): +    """ Remove a file if it exists """ +    try: +        os.remove(filename) +    except OSError as ose: +        if ose.errno != errno.ENOENT: +            raise +  class FakeYDL(YoutubeDL):      def __init__(self): -        self.result = []          # Different instances of the downloader can't share the same dictionary          # some test set the "sublang" parameter, which would break the md5 checks. -        self.params = dict(parameters) -    def to_screen(self, s): +        params = get_params() +        super(FakeYDL, self).__init__(params) +        self.result = [] +         +    def to_screen(self, s, skip_eol=None):          print(s) +      def trouble(self, s, tb=None):          raise Exception(s) +      def download(self, x):          self.result.append(x) +    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 +            old_report_warning(message) +        self.report_warning = types.MethodType(report_warning, self) +  def get_testcases():      for ie in youtube_dl.extractor.gen_extractors():          t = getattr(ie, '_TEST', None) @@ -42,3 +67,6 @@ def get_testcases():          for t in getattr(ie, '_TESTS', []):              t['name'] = type(ie).__name__[:-len('IE')]              yield t + + +md5 = lambda s: hashlib.md5(s.encode('utf-8')).hexdigest() diff --git a/test/parameters.json b/test/parameters.json index 96998b5c3..f042880ed 100644 --- a/test/parameters.json +++ b/test/parameters.json @@ -38,7 +38,6 @@      "writedescription": false,       "writeinfojson": true,       "writesubtitles": false, -    "onlysubtitles": false,      "allsubtitles": false,      "listssubtitles": false  } diff --git a/test/test_age_restriction.py b/test/test_age_restriction.py new file mode 100644 index 000000000..d500c6edc --- /dev/null +++ b/test/test_age_restriction.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +# 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 global_setup, try_rm +global_setup() + + +from youtube_dl import YoutubeDL + + +def _download_restricted(url, filename, age): +    """ Returns true iff the file has been downloaded """ + +    params = { +        'age_limit': age, +        'skip_download': True, +        'writeinfojson': True, +        "outtmpl": "%(id)s.%(ext)s", +    } +    ydl = YoutubeDL(params) +    ydl.add_default_info_extractors() +    json_filename = filename + '.info.json' +    try_rm(json_filename) +    ydl.download([url]) +    res = os.path.exists(json_filename) +    try_rm(json_filename) +    return res + + +class TestAgeRestriction(unittest.TestCase): +    def _assert_restricted(self, url, filename, age, old_age=None): +        self.assertTrue(_download_restricted(url, filename, old_age)) +        self.assertFalse(_download_restricted(url, filename, age)) + +    def test_youtube(self): +        self._assert_restricted('07FYdnEawAQ', '07FYdnEawAQ.mp4', 10) + +    def test_youporn(self): +        self._assert_restricted( +            '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 c73d0e467..56e5f80e1 100644 --- a/test/test_all_urls.py +++ b/test/test_all_urls.py @@ -1,34 +1,66 @@  #!/usr/bin/env python +# Allow direct execution +import os  import sys  import unittest +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -# Allow direct execution -import os -sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -from youtube_dl.extractor import YoutubeIE, YoutubePlaylistIE, YoutubeChannelIE, JustinTVIE, gen_extractors -from helper import get_testcases +from test.helper import get_testcases + +from youtube_dl.extractor import ( +    gen_extractors, +    JustinTVIE, +    YoutubeIE, +) +  class TestAllURLsMatching(unittest.TestCase): +    def setUp(self): +        self.ies = gen_extractors() + +    def matching_ies(self, url): +        return [ie.IE_NAME for ie in self.ies if ie.suitable(url) and ie.IE_NAME != 'generic'] + +    def assertMatch(self, url, ie_list): +        self.assertEqual(self.matching_ies(url), ie_list) +      def test_youtube_playlist_matching(self): -        self.assertTrue(YoutubePlaylistIE.suitable(u'ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')) -        self.assertTrue(YoutubePlaylistIE.suitable(u'UUBABnxM4Ar9ten8Mdjj1j0Q')) #585 -        self.assertTrue(YoutubePlaylistIE.suitable(u'PL63F0C78739B09958')) -        self.assertTrue(YoutubePlaylistIE.suitable(u'https://www.youtube.com/playlist?list=UUBABnxM4Ar9ten8Mdjj1j0Q')) -        self.assertTrue(YoutubePlaylistIE.suitable(u'https://www.youtube.com/course?list=ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8')) -        self.assertTrue(YoutubePlaylistIE.suitable(u'https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC')) -        self.assertTrue(YoutubePlaylistIE.suitable(u'https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012')) #668 -        self.assertFalse(YoutubePlaylistIE.suitable(u'PLtS2H6bU1M')) +        assertPlaylist = lambda url: self.assertMatch(url, ['youtube:playlist']) +        assertPlaylist(u'ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8') +        assertPlaylist(u'UUBABnxM4Ar9ten8Mdjj1j0Q') #585 +        assertPlaylist(u'PL63F0C78739B09958') +        assertPlaylist(u'https://www.youtube.com/playlist?list=UUBABnxM4Ar9ten8Mdjj1j0Q') +        assertPlaylist(u'https://www.youtube.com/course?list=ECUl4u3cNGP61MdtwGTqZA0MreSaDybji8') +        assertPlaylist(u'https://www.youtube.com/playlist?list=PLwP_SiAcdui0KVebT0mU9Apz359a4ubsC') +        assertPlaylist(u'https://www.youtube.com/watch?v=AV6J6_AeFEQ&playnext=1&list=PL4023E734DA416012') #668 +        self.assertFalse('youtube:playlist' in self.matching_ies(u'PLtS2H6bU1M'))      def test_youtube_matching(self):          self.assertTrue(YoutubeIE.suitable(u'PLtS2H6bU1M'))          self.assertFalse(YoutubeIE.suitable(u'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'])      def test_youtube_channel_matching(self): -        self.assertTrue(YoutubeChannelIE.suitable('https://www.youtube.com/channel/HCtnHdj3df7iM')) -        self.assertTrue(YoutubeChannelIE.suitable('https://www.youtube.com/channel/HCtnHdj3df7iM?feature=gb_ch_rec')) -        self.assertTrue(YoutubeChannelIE.suitable('https://www.youtube.com/channel/HCtnHdj3df7iM/videos')) +        assertChannel = lambda url: self.assertMatch(url, ['youtube:channel']) +        assertChannel('https://www.youtube.com/channel/HCtnHdj3df7iM') +        assertChannel('https://www.youtube.com/channel/HCtnHdj3df7iM?feature=gb_ch_rec') +        assertChannel('https://www.youtube.com/channel/HCtnHdj3df7iM/videos') + +    def test_youtube_user_matching(self): +        self.assertMatch('www.youtube.com/NASAgovVideo/videos', ['youtube:user']) + +    def test_youtube_feeds(self): +        self.assertMatch('https://www.youtube.com/feed/watch_later', ['youtube:watch_later']) +        self.assertMatch('https://www.youtube.com/feed/subscriptions', ['youtube:subscriptions']) +        self.assertMatch('https://www.youtube.com/feed/recommended', ['youtube:recommended']) +        self.assertMatch('https://www.youtube.com/my_favorites', ['youtube:favorites']) + +    def test_youtube_show_matching(self): +        self.assertMatch('http://www.youtube.com/show/airdisasters', ['youtube:show'])      def test_justin_tv_channelid_matching(self):          self.assertTrue(JustinTVIE.suitable(u"justin.tv/vanillatv")) @@ -47,9 +79,13 @@ class TestAllURLsMatching(unittest.TestCase):          self.assertTrue(JustinTVIE.suitable(u"http://www.twitch.tv/tsm_theoddone/c/2349361"))      def test_youtube_extract(self): -        self.assertEqual(YoutubeIE()._extract_id('http://www.youtube.com/watch?&v=BaW_jenozKc'), 'BaW_jenozKc') -        self.assertEqual(YoutubeIE()._extract_id('https://www.youtube.com/watch?&v=BaW_jenozKc'), 'BaW_jenozKc') -        self.assertEqual(YoutubeIE()._extract_id('https://www.youtube.com/watch?feature=player_embedded&v=BaW_jenozKc'), 'BaW_jenozKc') +        assertExtractId = lambda url, id: self.assertEqual(YoutubeIE()._extract_id(url), id) +        assertExtractId('http://www.youtube.com/watch?&v=BaW_jenozKc', 'BaW_jenozKc') +        assertExtractId('https://www.youtube.com/watch?&v=BaW_jenozKc', 'BaW_jenozKc') +        assertExtractId('https://www.youtube.com/watch?feature=player_embedded&v=BaW_jenozKc', 'BaW_jenozKc') +        assertExtractId('https://www.youtube.com/watch_popup?v=BaW_jenozKc', 'BaW_jenozKc') +        assertExtractId('http://www.youtube.com/watch?v=BaW_jenozKcsharePLED17F32AD9753930', 'BaW_jenozKc') +        assertExtractId('BaW_jenozKc', 'BaW_jenozKc')      def test_no_duplicates(self):          ies = gen_extractors() @@ -62,15 +98,12 @@ class TestAllURLsMatching(unittest.TestCase):                      self.assertFalse(ie.suitable(url), '%s should not match URL %r' % (type(ie).__name__, url))      def test_keywords(self): -        ies = gen_extractors() -        matching_ies = lambda url: [ie.IE_NAME for ie in ies -                                    if ie.suitable(url) and ie.IE_NAME != 'generic'] -        self.assertEqual(matching_ies(':ytsubs'), ['youtube:subscriptions']) -        self.assertEqual(matching_ies(':ytsubscriptions'), ['youtube:subscriptions']) -        self.assertEqual(matching_ies(':thedailyshow'), ['ComedyCentral']) -        self.assertEqual(matching_ies(':tds'), ['ComedyCentral']) -        self.assertEqual(matching_ies(':colbertreport'), ['ComedyCentral']) -        self.assertEqual(matching_ies(':cr'), ['ComedyCentral']) +        self.assertMatch(':ytsubs', ['youtube:subscriptions']) +        self.assertMatch(':ytsubscriptions', ['youtube:subscriptions']) +        self.assertMatch(':thedailyshow', ['ComedyCentral']) +        self.assertMatch(':tds', ['ComedyCentral']) +        self.assertMatch(':colbertreport', ['ComedyCentral']) +        self.assertMatch(':cr', ['ComedyCentral'])  if __name__ == '__main__': diff --git a/test/test_dailymotion_subtitles.py b/test/test_dailymotion_subtitles.py new file mode 100644 index 000000000..c596415c4 --- /dev/null +++ b/test/test_dailymotion_subtitles.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +# 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 FakeYDL, global_setup, md5 +global_setup() + + +from youtube_dl.extractor import DailymotionIE + +class TestDailymotionSubtitles(unittest.TestCase): +    def setUp(self): +        self.DL = FakeYDL() +        self.url = 'http://www.dailymotion.com/video/xczg00' +    def getInfoDict(self): +        IE = DailymotionIE(self.DL) +        info_dict = IE.extract(self.url) +        return info_dict +    def getSubtitles(self): +        info_dict = self.getInfoDict() +        return info_dict[0]['subtitles'] +    def test_no_writesubtitles(self): +        subtitles = self.getSubtitles() +        self.assertEqual(subtitles, None) +    def test_subtitles(self): +        self.DL.params['writesubtitles'] = True +        subtitles = self.getSubtitles() +        self.assertEqual(md5(subtitles['en']), '976553874490cba125086bbfea3ff76f') +    def test_subtitles_lang(self): +        self.DL.params['writesubtitles'] = True +        self.DL.params['subtitleslangs'] = ['fr'] +        subtitles = self.getSubtitles() +        self.assertEqual(md5(subtitles['fr']), '594564ec7d588942e384e920e5341792') +    def test_allsubtitles(self): +        self.DL.params['writesubtitles'] = True +        self.DL.params['allsubtitles'] = True +        subtitles = self.getSubtitles() +        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.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.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.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 +        subtitles = self.getSubtitles() +        self.assertEqual(len(subtitles), 0) +    def test_multiple_langs(self): +        self.DL.params['writesubtitles'] = True +        langs = ['es', 'fr', 'de'] +        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) + +if __name__ == '__main__': +    unittest.main() diff --git a/test/test_download.py b/test/test_download.py index 21cb2e694..b9a9be11d 100644 --- a/test/test_download.py +++ b/test/test_download.py @@ -1,43 +1,31 @@  #!/usr/bin/env python -import errno +# 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, get_testcases, global_setup, try_rm, md5 +global_setup() + +  import hashlib  import io -import os  import json -import unittest -import sys  import socket -import binascii - -# Allow direct execution -sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))  import youtube_dl.YoutubeDL -from youtube_dl.utils import * - -PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "parameters.json") +from youtube_dl.utils import ( +    compat_str, +    compat_urllib_error, +    DownloadError, +    ExtractorError, +    UnavailableVideoError, +)  RETRIES = 3 -# General configuration (from __init__, not very elegant...) -jar = compat_cookiejar.CookieJar() -cookie_processor = compat_urllib_request.HTTPCookieProcessor(jar) -proxy_handler = compat_urllib_request.ProxyHandler() -opener = compat_urllib_request.build_opener(proxy_handler, cookie_processor, YoutubeDLHandler()) -compat_urllib_request.install_opener(opener) -socket.setdefaulttimeout(10) - -def _try_rm(filename): -    """ Remove a file if it exists """ -    try: -        os.remove(filename) -    except OSError as ose: -        if ose.errno != errno.ENOENT: -            raise - -md5 = lambda s: hashlib.md5(s.encode('utf-8')).hexdigest() -  class YoutubeDL(youtube_dl.YoutubeDL):      def __init__(self, *args, **kwargs):          self.to_stderr = self.to_screen @@ -54,17 +42,12 @@ def _file_md5(fn):      with open(fn, 'rb') as f:          return hashlib.md5(f.read()).hexdigest() -from helper import get_testcases  defs = get_testcases() -with io.open(PARAMETERS_FILE, encoding='utf-8') as pf: -    parameters = json.load(pf) -  class TestDownload(unittest.TestCase):      maxDiff = None      def setUp(self): -        self.parameters = parameters          self.defs = defs  ### Dynamically generate tests @@ -84,8 +67,7 @@ def generator(test_case):              print_skipping(test_case['skip'])              return -        params = self.parameters.copy() -        params.update(test_case.get('params', {})) +        params = get_params(test_case.get('params', {}))          ydl = YoutubeDL(params)          ydl.add_default_info_extractors() @@ -97,9 +79,9 @@ def generator(test_case):          test_cases = test_case.get('playlist', [test_case])          for tc in test_cases: -            _try_rm(tc['file']) -            _try_rm(tc['file'] + '.part') -            _try_rm(tc['file'] + '.info.json') +            try_rm(tc['file']) +            try_rm(tc['file'] + '.part') +            try_rm(tc['file'] + '.info.json')          try:              for retry in range(1, RETRIES + 1):                  try: @@ -127,12 +109,11 @@ def generator(test_case):                      info_dict = json.load(infof)                  for (info_field, expected) in tc.get('info_dict', {}).items():                      if isinstance(expected, compat_str) and expected.startswith('md5:'): -                        self.assertEqual(expected, 'md5:' + md5(info_dict.get(info_field))) +                        got = 'md5:' + md5(info_dict.get(info_field))                      else:                          got = info_dict.get(info_field) -                        self.assertEqual( -                            expected, got, -                            u'invalid value for field %s, expected %r, got %r' % (info_field, expected, got)) +                    self.assertEqual(expected, got, +                        u'invalid value for field %s, expected %r, got %r' % (info_field, expected, got))                  # If checkable fields are missing from the test case, print the info_dict                  test_info_dict = dict((key, value if not isinstance(value, compat_str) or len(value) < 250 else 'md5:' + md5(value)) @@ -146,9 +127,9 @@ def generator(test_case):                      self.assertTrue(key in info_dict.keys() and info_dict[key])          finally:              for tc in test_cases: -                _try_rm(tc['file']) -                _try_rm(tc['file'] + '.part') -                _try_rm(tc['file'] + '.info.json') +                try_rm(tc['file']) +                try_rm(tc['file'] + '.part') +                try_rm(tc['file'] + '.info.json')      return test_template diff --git a/test/test_playlists.py b/test/test_playlists.py new file mode 100644 index 000000000..d6a8d56df --- /dev/null +++ b/test/test_playlists.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# encoding: 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 FakeYDL, global_setup +global_setup() + + +from youtube_dl.extractor import ( +    DailymotionPlaylistIE, +    DailymotionUserIE, +    VimeoChannelIE, +    UstreamChannelIE, +    SoundcloudUserIE, +    LivestreamIE, +    NHLVideocenterIE, +) + + +class TestPlaylists(unittest.TestCase): +    def assertIsPlaylist(self, info): +        """Make sure the info has '_type' set to 'playlist'""" +        self.assertEqual(info['_type'], 'playlist') + +    def test_dailymotion_playlist(self): +        dl = FakeYDL() +        ie = DailymotionPlaylistIE(dl) +        result = ie.extract('http://www.dailymotion.com/playlist/xv4bw_nqtv_sport/1#video=xl8v3q') +        self.assertIsPlaylist(result) +        self.assertEqual(result['title'], u'SPORT') +        self.assertTrue(len(result['entries']) > 20) + +    def test_dailymotion_user(self): +        dl = FakeYDL() +        ie = DailymotionUserIE(dl) +        result = ie.extract('http://www.dailymotion.com/user/generation-quoi/') +        self.assertIsPlaylist(result) +        self.assertEqual(result['title'], u'Génération Quoi') +        self.assertTrue(len(result['entries']) >= 26) + +    def test_vimeo_channel(self): +        dl = FakeYDL() +        ie = VimeoChannelIE(dl) +        result = ie.extract('http://vimeo.com/channels/tributes') +        self.assertIsPlaylist(result) +        self.assertEqual(result['title'], u'Vimeo Tributes') +        self.assertTrue(len(result['entries']) > 24) + +    def test_ustream_channel(self): +        dl = FakeYDL() +        ie = UstreamChannelIE(dl) +        result = ie.extract('http://www.ustream.tv/channel/young-americans-for-liberty') +        self.assertIsPlaylist(result) +        self.assertEqual(result['id'], u'5124905') +        self.assertTrue(len(result['entries']) >= 11) + +    def test_soundcloud_user(self): +        dl = FakeYDL() +        ie = SoundcloudUserIE(dl) +        result = ie.extract('https://soundcloud.com/the-concept-band') +        self.assertIsPlaylist(result) +        self.assertEqual(result['id'], u'9615865') +        self.assertTrue(len(result['entries']) >= 12) + +    def test_livestream_event(self): +        dl = FakeYDL() +        ie = LivestreamIE(dl) +        result = ie.extract('http://new.livestream.com/tedx/cityenglish') +        self.assertIsPlaylist(result) +        self.assertEqual(result['title'], u'TEDCity2.0 (English)') +        self.assertTrue(len(result['entries']) >= 4) + +    def test_nhl_videocenter(self): +        dl = FakeYDL() +        ie = NHLVideocenterIE(dl) +        result = ie.extract('http://video.canucks.nhl.com/videocenter/console?catid=999') +        self.assertIsPlaylist(result) +        self.assertEqual(result['id'], u'999') +        self.assertEqual(result['title'], u'Highlights') +        self.assertEqual(len(result['entries']), 12) + +if __name__ == '__main__': +    unittest.main() diff --git a/test/test_utils.py b/test/test_utils.py index be1069105..270669044 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -1,23 +1,27 @@  #!/usr/bin/env python -# Various small unit tests - +# Allow direct execution +import os  import sys  import unittest -import xml.etree.ElementTree +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -# Allow direct execution -import os -sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +# Various small unit tests +import xml.etree.ElementTree  #from youtube_dl.utils import htmlentity_transform -from youtube_dl.utils import timeconvert -from youtube_dl.utils import sanitize_filename -from youtube_dl.utils import unescapeHTML -from youtube_dl.utils import orderedSet -from youtube_dl.utils import DateRange -from youtube_dl.utils import unified_strdate -from youtube_dl.utils import find_xpath_attr +from youtube_dl.utils import ( +    timeconvert, +    sanitize_filename, +    unescapeHTML, +    orderedSet, +    DateRange, +    unified_strdate, +    find_xpath_attr, +    get_meta_content, +    xpath_with_ns, +)  if sys.version_info < (3, 0):      _compat_str = lambda b: b.decode('unicode-escape') @@ -127,5 +131,29 @@ 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 = u''' +        <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'), u'foo & bar') +        self.assertEqual(get_meta('author'), 'Plato') + +    def test_xpath_with_ns(self): +        testxml = u'''<root xmlns:media="http://example.com/"> +            <media:song> +                <media:author>The Author</media:author> +                <url>http://server.com/download.mp3</url> +            </media:song> +        </root>''' +        doc = xml.etree.ElementTree.fromstring(testxml) +        find = lambda p: doc.find(xpath_with_ns(p, {'media': 'http://example.com/'})) +        self.assertTrue(find('media:song') is not None) +        self.assertEqual(find('media:song/media:author').text, u'The Author') +        self.assertEqual(find('media:song/url').text, u'http://server.com/download.mp3') +  if __name__ == '__main__':      unittest.main() diff --git a/test/test_write_annotations.py b/test/test_write_annotations.py new file mode 100644 index 000000000..6f08808cd --- /dev/null +++ b/test/test_write_annotations.py @@ -0,0 +1,81 @@ +#!/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, global_setup, try_rm +global_setup() + + +import io + +import xml.etree.ElementTree + +import youtube_dl.YoutubeDL +import youtube_dl.extractor +from youtube_dl.utils import True + + +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({ +    'writeannotations': True, +    'skip_download': True, +    'writeinfojson': False, +    'format': 'flv', +}) + + + +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. +        ie = youtube_dl.extractor.YoutubeIE() +        ydl = YoutubeDL(params) +        ydl.add_info_extractor(ie) +        ydl.download([TEST_ID]) +        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) +        self.assertTrue(annoxml is not None, 'Failed to parse annotations XML') +        root = annoxml.getroot() +        self.assertEqual(root.tag, 'document') +        annotationsTag = root.find('annotations') +        self.assertEqual(annotationsTag.tag, 'annotations') +        annotations = annotationsTag.findall('annotation') + +        #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(len(expected), 0, 'Not all expected annotations were found.') +         + +    def tearDown(self): +        try_rm(ANNOTATIONS_FILE) + +if __name__ == '__main__': +    unittest.main() diff --git a/test/test_write_info_json.py b/test/test_write_info_json.py index de6d5180f..a5b6f6972 100644 --- a/test/test_write_info_json.py +++ b/test/test_write_info_json.py @@ -1,37 +1,34 @@  #!/usr/bin/env python  # coding: utf-8 -import json +# Allow direct execution  import os  import sys  import unittest +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -# Allow direct execution -sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from test.helper import get_params, global_setup +global_setup() + + +import io +import json  import youtube_dl.YoutubeDL  import youtube_dl.extractor -from youtube_dl.utils import * - -PARAMETERS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "parameters.json") -# General configuration (from __init__, not very elegant...) -jar = compat_cookiejar.CookieJar() -cookie_processor = compat_urllib_request.HTTPCookieProcessor(jar) -proxy_handler = compat_urllib_request.ProxyHandler() -opener = compat_urllib_request.build_opener(proxy_handler, cookie_processor, YoutubeDLHandler()) -compat_urllib_request.install_opener(opener)  class YoutubeDL(youtube_dl.YoutubeDL):      def __init__(self, *args, **kwargs):          super(YoutubeDL, self).__init__(*args, **kwargs)          self.to_stderr = self.to_screen -with io.open(PARAMETERS_FILE, encoding='utf-8') as pf: -    params = json.load(pf) -params['writeinfojson'] = True -params['skip_download'] = True -params['writedescription'] = True +params = get_params({ +    'writeinfojson': True, +    'skip_download': True, +    'writedescription': True, +}) +  TEST_ID = 'BaW_jenozKc'  INFO_JSON_FILE = TEST_ID + '.mp4.info.json' @@ -42,6 +39,7 @@ 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 diff --git a/test/test_youtube_lists.py b/test/test_youtube_lists.py index dd9e292b0..c1753b5bb 100644 --- a/test/test_youtube_lists.py +++ b/test/test_youtube_lists.py @@ -1,20 +1,26 @@  #!/usr/bin/env python +# Allow direct execution +import os  import sys  import unittest -import json +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -# Allow direct execution -import os -sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +from test.helper import FakeYDL, global_setup +global_setup() -from youtube_dl.extractor import YoutubeUserIE, YoutubePlaylistIE, YoutubeIE, YoutubeChannelIE, YoutubeShowIE -from youtube_dl.utils import * -from helper import FakeYDL +from youtube_dl.extractor import ( +    YoutubeUserIE, +    YoutubePlaylistIE, +    YoutubeIE, +    YoutubeChannelIE, +    YoutubeShowIE, +) +  class TestYoutubeLists(unittest.TestCase): -    def assertIsPlaylist(self,info): +    def assertIsPlaylist(self, info):          """Make sure the info has '_type' set to 'playlist'"""          self.assertEqual(info['_type'], 'playlist') @@ -27,6 +33,14 @@ class TestYoutubeLists(unittest.TestCase):          ytie_results = [YoutubeIE()._extract_id(url['url']) for url in result['entries']]          self.assertEqual(ytie_results, [ 'bV9L5Ht9LgY', 'FXxLjLQi3Fg', 'tU3Bgo5qJZE']) +    def test_youtube_playlist_noplaylist(self): +        dl = FakeYDL() +        dl.params['noplaylist'] = True +        ie = YoutubePlaylistIE(dl) +        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_issue_673(self):          dl = FakeYDL()          ie = YoutubePlaylistIE(dl) diff --git a/test/test_youtube_sig.py b/test/test_youtube_sig.py deleted file mode 100755 index bbeb3e2fb..000000000 --- a/test/test_youtube_sig.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python - -import unittest -import sys - -# Allow direct execution -import os -sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - -from youtube_dl.extractor.youtube import YoutubeIE -from helper import FakeYDL - -sig = YoutubeIE(FakeYDL())._decrypt_signature - -class TestYoutubeSig(unittest.TestCase): -    def test_43_43(self): -        wrong = '5AEEAE0EC39677BC65FD9021CCD115F1F2DBD5A59E4.C0B243A3E2DED6769199AF3461781E75122AE135135' -        right = '931EA22157E1871643FA9519676DED253A342B0C.4E95A5DBD2F1F511DCC1209DF56CB77693CE0EAE' -        self.assertEqual(sig(wrong), right) - -    def test_88(self): -        wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[]}|:;?/>.<" -        right = "J:|}][{=+-_)(*&;%$#@>MNBVCXZASDFGH^KLPOIUYTREWQ0987654321mnbvcxzasdfghrklpoiuytej" -        self.assertEqual(sig(wrong), right) - -    def test_87(self): -        wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$^&*()_-+={[]}|:;?/>.<" -        right = "!?;:|}][{=+-_)(*&^$#@/MNBVCXZASqFGHJKLPOIUYTREWQ0987654321mnbvcxzasdfghjklpoiuytr" -        self.assertEqual(sig(wrong), right) - -    def test_86(self): -        wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[|};?/>.<" -        right = "ertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!/#$%^&*()_-+={[|};?@" -        self.assertEqual(sig(wrong), right) - -    def test_85(self): -        wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[};?/>.<" -        right = "{>/?;}[.=+-_)(*&^%$#@!MqBVCXZASDFwHJKLPOIUYTREWQ0987654321mnbvcxzasdfghjklpoiuytr" -        self.assertEqual(sig(wrong), right) - -    def test_84(self): -        wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!@#$%^&*()_-+={[};?>.<" -        right = "<.>?;}[{=+-_)(*&^%$#@!MNBVCXZASDFGHJKLPOIUYTREWe098765432rmnbvcxzasdfghjklpoiuyt1" -        self.assertEqual(sig(wrong), right) - -    def test_83(self): -        wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKJHGFDSAZXCVBNM!#$%^&*()_+={[};?/>.<" -        right = "urty8ioplkjhgfdsazxcvbqm1234567S90QWERTYUIOPLKJHGFDnAZXCVBNM!#$%^&*()_+={[};?/>.<" -        self.assertEqual(sig(wrong), right) - -    def test_82(self): -        wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKHGFDSAZXCVBNM!@#$%^&*(-+={[};?/>.<" -        right = "Q>/?;}[{=+-(*<^%$#@!MNBVCXZASDFGHKLPOIUY8REWT0q&7654321mnbvcxzasdfghjklpoiuytrew9" -        self.assertEqual(sig(wrong), right) - -    def test_81(self): -        wrong = "qwertyuioplkjhgfdsazxcvbnm1234567890QWERTYUIOPLKHGFDSAZXCVBNM!@#$%^&*(-+={[};?/>." -        right = "urty8ioplkjhgfdsazxcvbqm1234567e90QWERTYUIOPLKHGFDSnZXCVBNM!@#$%^&*(-+={[};?/>." -        self.assertEqual(sig(wrong), right) - -if __name__ == '__main__': -    unittest.main() diff --git a/test/test_youtube_signature.py b/test/test_youtube_signature.py new file mode 100644 index 000000000..5e1ff5eb0 --- /dev/null +++ b/test/test_youtube_signature.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python + +# 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 global_setup +global_setup() + + +import io +import re +import string + +from youtube_dl.extractor import YoutubeIE +from youtube_dl.utils import compat_str, compat_urlretrieve + +_TESTS = [ +    ( +        u'https://s.ytimg.com/yts/jsbin/html5player-vflHOr_nV.js', +        u'js', +        86, +        u'>=<;:/.-[+*)(\'&%$#"!ZYX0VUTSRQPONMLKJIHGFEDCBA\\yxwvutsrqponmlkjihgfedcba987654321', +    ), +    ( +        u'https://s.ytimg.com/yts/jsbin/html5player-vfldJ8xgI.js', +        u'js', +        85, +        u'3456789a0cdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS[UVWXYZ!"#$%&\'()*+,-./:;<=>?@', +    ), +    ( +        u'https://s.ytimg.com/yts/swfbin/watch_as3-vflg5GhxU.swf', +        u'swf', +        82, +        u':/.-,+*)=\'&%$#"!ZYX0VUTSRQPONMLKJIHGFEDCBAzyxw>utsrqponmlkjihgfedcba987654321' +    ), +] + + +class TestSignature(unittest.TestCase): +    def setUp(self): +        TEST_DIR = os.path.dirname(os.path.abspath(__file__)) +        self.TESTDATA_DIR = os.path.join(TEST_DIR, 'testdata') +        if not os.path.exists(self.TESTDATA_DIR): +            os.mkdir(self.TESTDATA_DIR) + + +def make_tfunc(url, stype, sig_length, expected_sig): +    basename = url.rpartition('/')[2] +    m = re.match(r'.*-([a-zA-Z0-9_-]+)\.[a-z]+$', basename) +    assert m, '%r should follow URL format' % basename +    test_id = m.group(1) + +    def test_func(self): +        fn = os.path.join(self.TESTDATA_DIR, basename) + +        if not os.path.exists(fn): +            compat_urlretrieve(url, fn) + +        ie = YoutubeIE() +        if stype == 'js': +            with io.open(fn, encoding='utf-8') as testf: +                jscode = testf.read() +            func = ie._parse_sig_js(jscode) +        else: +            assert stype == 'swf' +            with open(fn, 'rb') as testf: +                swfcode = testf.read() +            func = ie._parse_sig_swf(swfcode) +        src_sig = compat_str(string.printable[:sig_length]) +        got_sig = func(src_sig) +        self.assertEqual(got_sig, expected_sig) + +    test_func.__name__ = str('test_signature_' + stype + '_' + test_id) +    setattr(TestSignature, test_func.__name__, test_func) + +for test_spec in _TESTS: +    make_tfunc(*test_spec) + + +if __name__ == '__main__': +    unittest.main() diff --git a/test/test_youtube_subtitles.py b/test/test_youtube_subtitles.py index 86e09c9b1..00430a338 100644 --- a/test/test_youtube_subtitles.py +++ b/test/test_youtube_subtitles.py @@ -1,95 +1,95 @@  #!/usr/bin/env python +# Allow direct execution +import os  import sys  import unittest -import json -import io -import hashlib +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from test.helper import FakeYDL, global_setup, md5 +global_setup() -# Allow direct execution -import os -sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))  from youtube_dl.extractor import YoutubeIE -from youtube_dl.utils import * -from helper import FakeYDL -md5 = lambda s: hashlib.md5(s.encode('utf-8')).hexdigest()  class TestYoutubeSubtitles(unittest.TestCase):      def setUp(self): -        DL = FakeYDL() -        DL.params['allsubtitles'] = False -        DL.params['writesubtitles'] = False -        DL.params['subtitlesformat'] = 'srt' -        DL.params['listsubtitles'] = False -    def test_youtube_no_subtitles(self): -        DL = FakeYDL() -        DL.params['writesubtitles'] = False -        IE = YoutubeIE(DL) -        info_dict = IE.extract('QRS8MkLhQmM') -        subtitles = info_dict[0]['subtitles'] +        self.DL = FakeYDL() +        self.url = 'QRS8MkLhQmM' + +    def getInfoDict(self): +        IE = YoutubeIE(self.DL) +        info_dict = IE.extract(self.url) +        return info_dict + +    def getSubtitles(self): +        info_dict = self.getInfoDict() +        return info_dict[0]['subtitles'] + +    def test_youtube_no_writesubtitles(self): +        self.DL.params['writesubtitles'] = False +        subtitles = self.getSubtitles()          self.assertEqual(subtitles, None) +      def test_youtube_subtitles(self): -        DL = FakeYDL() -        DL.params['writesubtitles'] = True -        IE = YoutubeIE(DL) -        info_dict = IE.extract('QRS8MkLhQmM') -        sub = info_dict[0]['subtitles'][0] -        self.assertEqual(md5(sub[2]), '4cd9278a35ba2305f47354ee13472260') -    def test_youtube_subtitles_it(self): -        DL = FakeYDL() -        DL.params['writesubtitles'] = True -        DL.params['subtitleslang'] = 'it' -        IE = YoutubeIE(DL) -        info_dict = IE.extract('QRS8MkLhQmM') -        sub = info_dict[0]['subtitles'][0] -        self.assertEqual(md5(sub[2]), '164a51f16f260476a05b50fe4c2f161d') -    def test_youtube_onlysubtitles(self): -        DL = FakeYDL() -        DL.params['writesubtitles'] = True -        DL.params['onlysubtitles'] = True -        IE = YoutubeIE(DL) -        info_dict = IE.extract('QRS8MkLhQmM') -        sub = info_dict[0]['subtitles'][0] -        self.assertEqual(md5(sub[2]), '4cd9278a35ba2305f47354ee13472260') +        self.DL.params['writesubtitles'] = True +        subtitles = self.getSubtitles() +        self.assertEqual(md5(subtitles['en']), '4cd9278a35ba2305f47354ee13472260') + +    def test_youtube_subtitles_lang(self): +        self.DL.params['writesubtitles'] = True +        self.DL.params['subtitleslangs'] = ['it'] +        subtitles = self.getSubtitles() +        self.assertEqual(md5(subtitles['it']), '164a51f16f260476a05b50fe4c2f161d') +      def test_youtube_allsubtitles(self): -        DL = FakeYDL() -        DL.params['allsubtitles'] = True -        IE = YoutubeIE(DL) -        info_dict = IE.extract('QRS8MkLhQmM') -        subtitles = info_dict[0]['subtitles'] -        self.assertEqual(len(subtitles), 13) +        self.DL.params['writesubtitles'] = True +        self.DL.params['allsubtitles'] = True +        subtitles = self.getSubtitles() +        self.assertEqual(len(subtitles.keys()), 13) +      def test_youtube_subtitles_sbv_format(self): -        DL = FakeYDL() -        DL.params['writesubtitles'] = True -        DL.params['subtitlesformat'] = 'sbv' -        IE = YoutubeIE(DL) -        info_dict = IE.extract('QRS8MkLhQmM') -        sub = info_dict[0]['subtitles'][0] -        self.assertEqual(md5(sub[2]), '13aeaa0c245a8bed9a451cb643e3ad8b') +        self.DL.params['writesubtitles'] = True +        self.DL.params['subtitlesformat'] = 'sbv' +        subtitles = self.getSubtitles() +        self.assertEqual(md5(subtitles['en']), '13aeaa0c245a8bed9a451cb643e3ad8b') +      def test_youtube_subtitles_vtt_format(self): -        DL = FakeYDL() -        DL.params['writesubtitles'] = True -        DL.params['subtitlesformat'] = 'vtt' -        IE = YoutubeIE(DL) -        info_dict = IE.extract('QRS8MkLhQmM') -        sub = info_dict[0]['subtitles'][0] -        self.assertEqual(md5(sub[2]), '356cdc577fde0c6783b9b822e7206ff7') +        self.DL.params['writesubtitles'] = True +        self.DL.params['subtitlesformat'] = 'vtt' +        subtitles = self.getSubtitles() +        self.assertEqual(md5(subtitles['en']), '356cdc577fde0c6783b9b822e7206ff7') +      def test_youtube_list_subtitles(self): -        DL = FakeYDL() -        DL.params['listsubtitles'] = True -        IE = YoutubeIE(DL) -        info_dict = IE.extract('QRS8MkLhQmM') +        self.DL.expect_warning(u'Video doesn\'t have automatic captions') +        self.DL.params['listsubtitles'] = True +        info_dict = self.getInfoDict()          self.assertEqual(info_dict, None) +      def test_youtube_automatic_captions(self): -        DL = FakeYDL() -        DL.params['writeautomaticsub'] = True -        DL.params['subtitleslang'] = 'it' -        IE = YoutubeIE(DL) -        info_dict = IE.extract('8YoUxe5ncPo') -        sub = info_dict[0]['subtitles'][0] -        self.assertTrue(sub[2] is not None) +        self.url = '8YoUxe5ncPo' +        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.url = 'sAjKT8FhjI8' +        self.DL.params['writesubtitles'] = True +        self.DL.params['allsubtitles'] = True +        subtitles = self.getSubtitles() +        self.assertEqual(len(subtitles), 0) + +    def test_youtube_multiple_langs(self): +        self.url = 'QRS8MkLhQmM' +        self.DL.params['writesubtitles'] = True +        langs = ['it', 'fr', 'de'] +        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)  if __name__ == '__main__':      unittest.main()  | 
