Aluode/PerceptionLabPortable
0
1"""Tests for distutils.util."""2 3import email4import email.generator5import email.policy6import io7import os8import pathlib9import sys10import sysconfig as stdlib_sysconfig11import unittest.mock as mock12from copy import copy13from distutils import sysconfig, util14from distutils.errors import DistutilsByteCompileError, DistutilsPlatformError15from distutils.util import (16 byte_compile,17 change_root,18 check_environ,19 convert_path,20 get_host_platform,21 get_platform,22 grok_environment_error,23 rfc822_escape,24 split_quoted,25 strtobool,26)27 28import pytest29 30 31@pytest.fixture(autouse=True)32def environment(monkeypatch):33 monkeypatch.setattr(os, 'name', os.name)34 monkeypatch.setattr(sys, 'platform', sys.platform)35 monkeypatch.setattr(sys, 'version', sys.version)36 monkeypatch.setattr(os, 'sep', os.sep)37 monkeypatch.setattr(os.path, 'join', os.path.join)38 monkeypatch.setattr(os.path, 'isabs', os.path.isabs)39 monkeypatch.setattr(os.path, 'splitdrive', os.path.splitdrive)40 monkeypatch.setattr(sysconfig, '_config_vars', copy(sysconfig._config_vars))41 42 43@pytest.mark.usefixtures('save_env')44class TestUtil:45 def test_get_host_platform(self):46 with mock.patch('os.name', 'nt'):47 with mock.patch('sys.version', '... [... (ARM64)]'):48 assert get_host_platform() == 'win-arm64'49 with mock.patch('sys.version', '... [... (ARM)]'):50 assert get_host_platform() == 'win-arm32'51 52 with mock.patch('sys.version_info', (3, 9, 0, 'final', 0)):53 assert get_host_platform() == stdlib_sysconfig.get_platform()54 55 def test_get_platform(self):56 with mock.patch('os.name', 'nt'):57 with mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'x86'}):58 assert get_platform() == 'win32'59 with mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'x64'}):60 assert get_platform() == 'win-amd64'61 with mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'arm'}):62 assert get_platform() == 'win-arm32'63 with mock.patch.dict('os.environ', {'VSCMD_ARG_TGT_ARCH': 'arm64'}):64 assert get_platform() == 'win-arm64'65 66 def test_convert_path(self):67 expected = os.sep.join(('', 'home', 'to', 'my', 'stuff'))68 assert convert_path('/home/to/my/stuff') == expected69 assert convert_path(pathlib.Path('/home/to/my/stuff')) == expected70 assert convert_path('.') == os.curdir71 72 def test_change_root(self):73 # linux/mac74 os.name = 'posix'75 76 def _isabs(path):77 return path[0] == '/'78 79 os.path.isabs = _isabs80 81 def _join(*path):82 return '/'.join(path)83 84 os.path.join = _join85 86 assert change_root('/root', '/old/its/here') == '/root/old/its/here'87 assert change_root('/root', 'its/here') == '/root/its/here'88 89 # windows90 os.name = 'nt'91 os.sep = '\\'92 93 def _isabs(path):94 return path.startswith('c:\\')95 96 os.path.isabs = _isabs97 98 def _splitdrive(path):99 if path.startswith('c:'):100 return ('', path.replace('c:', ''))101 return ('', path)102 103 os.path.splitdrive = _splitdrive104 105 def _join(*path):106 return '\\'.join(path)107 108 os.path.join = _join109 110 assert (111 change_root('c:\\root', 'c:\\old\\its\\here') == 'c:\\root\\old\\its\\here'112 )113 assert change_root('c:\\root', 'its\\here') == 'c:\\root\\its\\here'114 115 # BugsBunny os (it's a great os)116 os.name = 'BugsBunny'117 with pytest.raises(DistutilsPlatformError):118 change_root('c:\\root', 'its\\here')119 120 # XXX platforms to be covered: mac121 122 def test_check_environ(self):123 util.check_environ.cache_clear()124 os.environ.pop('HOME', None)125 126 check_environ()127 128 assert os.environ['PLAT'] == get_platform()129 130 @pytest.mark.skipif("os.name != 'posix'")131 def test_check_environ_getpwuid(self):132 util.check_environ.cache_clear()133 os.environ.pop('HOME', None)134 135 import pwd136 137 # only set pw_dir field, other fields are not used138 result = pwd.struct_passwd((139 None,140 None,141 None,142 None,143 None,144 '/home/distutils',145 None,146 ))147 with mock.patch.object(pwd, 'getpwuid', return_value=result):148 check_environ()149 assert os.environ['HOME'] == '/home/distutils'150 151 util.check_environ.cache_clear()152 os.environ.pop('HOME', None)153 154 # bpo-10496: Catch pwd.getpwuid() error155 with mock.patch.object(pwd, 'getpwuid', side_effect=KeyError):156 check_environ()157 assert 'HOME' not in os.environ158 159 def test_split_quoted(self):160 assert split_quoted('""one"" "two" \'three\' \\four') == [161 'one',162 'two',163 'three',164 'four',165 ]166 167 def test_strtobool(self):168 yes = ('y', 'Y', 'yes', 'True', 't', 'true', 'True', 'On', 'on', '1')169 no = ('n', 'no', 'f', 'false', 'off', '0', 'Off', 'No', 'N')170 171 for y in yes:172 assert strtobool(y)173 174 for n in no:175 assert not strtobool(n)176 177 indent = 8 * ' '178 179 @pytest.mark.parametrize(180 "given,wanted",181 [182 # 0x0b, 0x0c, ..., etc are also considered a line break by Python183 ("hello\x0b\nworld\n", f"hello\x0b{indent}\n{indent}world\n{indent}"),184 ("hello\x1eworld", f"hello\x1e{indent}world"),185 ("", ""),186 (187 "I am a\npoor\nlonesome\nheader\n",188 f"I am a\n{indent}poor\n{indent}lonesome\n{indent}header\n{indent}",189 ),190 ],191 )192 def test_rfc822_escape(self, given, wanted):193 """194 We want to ensure a multi-line header parses correctly.195 196 For interoperability, the escaped value should also "round-trip" over197 `email.generator.Generator.flatten` and `email.message_from_*`198 (see pypa/setuptools#4033).199 200 The main issue is that internally `email.policy.EmailPolicy` uses201 `splitlines` which will split on some control chars. If all the new lines202 are not prefixed with spaces, the parser will interrupt reading203 the current header and produce an incomplete value, while204 incorrectly interpreting the rest of the headers as part of the payload.205 """206 res = rfc822_escape(given)207 208 policy = email.policy.EmailPolicy(209 utf8=True,210 mangle_from_=False,211 max_line_length=0,212 )213 with io.StringIO() as buffer:214 raw = f"header: {res}\nother-header: 42\n\npayload\n"215 orig = email.message_from_string(raw)216 email.generator.Generator(buffer, policy=policy).flatten(orig)217 buffer.seek(0)218 regen = email.message_from_file(buffer)219 220 for msg in (orig, regen):221 assert msg.get_payload() == "payload\n"222 assert msg["other-header"] == "42"223 # Generator may replace control chars with `\n`224 assert set(msg["header"].splitlines()) == set(res.splitlines())225 226 assert res == wanted227 228 def test_dont_write_bytecode(self):229 # makes sure byte_compile raise a DistutilsError230 # if sys.dont_write_bytecode is True231 old_dont_write_bytecode = sys.dont_write_bytecode232 sys.dont_write_bytecode = True233 try:234 with pytest.raises(DistutilsByteCompileError):235 byte_compile([])236 finally:237 sys.dont_write_bytecode = old_dont_write_bytecode238 239 def test_grok_environment_error(self):240 # test obsolete function to ensure backward compat (#4931)241 exc = OSError("Unable to find batch file")242 msg = grok_environment_error(exc)243 assert msg == "error: Unable to find batch file"244 