3 # Allow direct execution
9 sys
.path
.insert(0, os
.path
.dirname(os
.path
.dirname(os
.path
.abspath(__file__
))))
13 from pathlib
import Path
15 from yt_dlp
.compat
import compat_expanduser
16 from yt_dlp
.options
import create_parser
, parseOpts
17 from yt_dlp
.utils
import Config
, get_executable_path
21 'XDG_CONFIG_HOME': '/_xdg_config_home/',
22 'USERPROFILE': 'C:/Users/testing/',
23 'APPDATA': 'C:/Users/testing/AppData/Roaming/',
25 'HOMEPATH': 'Users/testing/',
29 @contextlib.contextmanager
30 def set_environ(**kwargs
):
31 saved_environ
= os
.environ
.copy()
33 for name
, value
in {**ENVIRON_DEFAULTS
, **kwargs
}.items():
35 os
.environ
.pop(name
, None)
37 os
.environ
[name
] = value
42 os
.environ
.update(saved_environ
)
45 def _generate_expected_groups():
46 xdg_config_home
= os
.getenv('XDG_CONFIG_HOME') or compat_expanduser('~/.config')
47 appdata_dir
= os
.getenv('appdata')
48 home_dir
= compat_expanduser('~')
51 Path(get_executable_path(), 'yt-dlp.conf'),
57 Path(xdg_config_home
, 'yt-dlp.conf'),
58 Path(xdg_config_home
, 'yt-dlp', 'config'),
59 Path(xdg_config_home
, 'yt-dlp', 'config.txt'),
61 Path(appdata_dir
, 'yt-dlp.conf'),
62 Path(appdata_dir
, 'yt-dlp', 'config'),
63 Path(appdata_dir
, 'yt-dlp', 'config.txt'),
64 ) if appdata_dir
else ()),
65 Path(home_dir
, 'yt-dlp.conf'),
66 Path(home_dir
, 'yt-dlp.conf.txt'),
67 Path(home_dir
, '.yt-dlp', 'config'),
68 Path(home_dir
, '.yt-dlp', 'config.txt'),
71 Path('/etc/yt-dlp.conf'),
72 Path('/etc/yt-dlp/config'),
73 Path('/etc/yt-dlp/config.txt'),
78 class TestConfig(unittest
.TestCase
):
82 def test_config__ENVIRON_DEFAULTS_sanity(self
):
83 expected
= make_expected()
84 self
.assertCountEqual(
85 set(expected
), expected
,
86 'ENVIRON_DEFAULTS produces non unique names')
88 def test_config_all_environ_values(self
):
89 for name
, value
in ENVIRON_DEFAULTS
.items():
90 for new_value
in (None, '', '.', value
or '/some/dir'):
91 with
set_environ(**{name
: new_value
}):
92 self
._simple
_grouping
_test
()
94 def test_config_default_expected_locations(self
):
95 files
, _
= self
._simple
_config
_test
()
97 files
, make_expected(),
98 'Not all expected locations have been checked')
100 def test_config_default_grouping(self
):
101 self
._simple
_grouping
_test
()
103 def _simple_grouping_test(self
):
104 expected_groups
= make_expected_groups()
105 for name
, group
in expected_groups
.items():
106 for index
, existing_path
in enumerate(group
):
107 result
, opts
= self
._simple
_config
_test
(existing_path
)
108 expected
= expected_from_expected_groups(expected_groups
, existing_path
)
111 f
'The checked locations do not match the expected ({name}, {index})')
113 opts
.outtmpl
['default'], '1',
114 f
'The used result value was incorrect ({name}, {index})')
116 def _simple_config_test(self
, *stop_paths
):
120 def read_file(filename
, default
=[]):
122 path
= Path(filename
)
124 if path
in stop_paths
:
126 return ['-o', f
'{encountered}']
128 with
ConfigMock(read_file
):
129 _
, opts
, _
= parseOpts([], False)
134 def test_config_early_exit_commandline(self
):
135 self
._early
_exit
_test
(0, '--ignore-config')
138 def test_config_early_exit_files(self
):
139 for index
, _
in enumerate(make_expected(), 1):
140 self
._early
_exit
_test
(index
)
142 def _early_exit_test(self
, allowed_reads
, *args
):
145 def read_file(filename
, default
=[]):
149 if reads
> allowed_reads
:
150 self
.fail('The remaining config was not ignored')
151 elif reads
== allowed_reads
:
152 return ['--ignore-config']
154 with
ConfigMock(read_file
):
155 parseOpts(args
, False)
158 def test_config_override_commandline(self
):
159 self
._override
_test
(0, '-o', 'pass')
162 def test_config_override_files(self
):
163 for index
, _
in enumerate(make_expected(), 1):
164 self
._override
_test
(index
)
166 def _override_test(self
, start_index
, *args
):
169 def read_file(filename
, default
=[]):
173 if index
> start_index
:
174 return ['-o', 'fail']
175 elif index
== start_index
:
176 return ['-o', 'pass']
178 with
ConfigMock(read_file
):
179 _
, opts
, _
= parseOpts(args
, False)
182 opts
.outtmpl
['default'], 'pass',
183 'The earlier group did not override the later ones')
186 @contextlib.contextmanager
187 def ConfigMock(read_file
=None):
188 with unittest
.mock
.patch('yt_dlp.options.Config') as mock
:
189 mock
.return_value
= Config(create_parser())
190 if read_file
is not None:
191 mock
.read_file
= read_file
196 def make_expected(*filepaths
):
197 return expected_from_expected_groups(_generate_expected_groups(), *filepaths
)
200 def make_expected_groups(*filepaths
):
201 return _filter_expected_groups(_generate_expected_groups(), filepaths
)
204 def expected_from_expected_groups(expected_groups
, *filepaths
):
205 return list(itertools
.chain
.from_iterable(
206 _filter_expected_groups(expected_groups
, filepaths
).values()))
209 def _filter_expected_groups(expected
, filepaths
):
214 for group
, paths
in expected
.items():
217 new_paths
.append(path
)
218 if path
in filepaths
:
221 result
[group
] = new_paths
226 if __name__
== '__main__':