|
5 | 5 | import pytest
|
6 | 6 |
|
7 | 7 | from pyls import uris
|
| 8 | +from pyls.python_ls import PythonLanguageServer |
8 | 9 |
|
9 | 10 | PY2 = sys.version_info.major == 2
|
10 | 11 |
|
11 | 12 | if PY2:
|
12 | 13 | import pathlib2 as pathlib
|
| 14 | + from StringIO import StringIO |
13 | 15 | else:
|
14 | 16 | import pathlib
|
| 17 | + from io import StringIO |
15 | 18 |
|
16 | 19 |
|
17 | 20 | DOC_URI = uris.from_fs_path(__file__)
|
@@ -119,3 +122,124 @@ def test_multiple_workspaces(tmpdir, pyls):
|
119 | 122 | pyls.m_workspace__did_change_workspace_folders(
|
120 | 123 | added=[], removed=[added_workspaces[0]])
|
121 | 124 | assert workspace1_uri not in pyls.workspaces
|
| 125 | + |
| 126 | + |
| 127 | +def _make_paths_dir_relative(paths, dirname): |
| 128 | + """Make paths relative to dirname |
| 129 | +
|
| 130 | + This method assumes below for simplicity: |
| 131 | +
|
| 132 | + - if a path in paths is relative, it is relative to "root" |
| 133 | + - dirname must be relative to "root" |
| 134 | + - empty dirname means "root" itself |
| 135 | + - neither "." nor ".." is allowed for dirname |
| 136 | + """ |
| 137 | + to_root = os.path.join(*(['..'] * len(dirname.split(os.path.sep)))) if dirname else '' |
| 138 | + return list(p if os.path.isabs(p) else os.path.join(to_root, p) for p in paths) |
| 139 | + |
| 140 | + |
| 141 | +@pytest.mark.parametrize('metafile', [ |
| 142 | + 'setup.cfg', |
| 143 | + 'tox.ini', |
| 144 | + 'service/foo/setup.cfg', |
| 145 | + 'service/foo/tox.ini', |
| 146 | +]) |
| 147 | +def test_source_roots_config(tmpdir, metafile): |
| 148 | + """Examine that source_roots config is intentionaly read in. |
| 149 | +
|
| 150 | + This test also examines below for entries in source_roots: |
| 151 | +
|
| 152 | + * absolute path is ignored |
| 153 | + * relative path is: |
| 154 | + - ignored, if it does not refer inside of the workspace |
| 155 | + - otherwise, it is treated as relative to config file location, and |
| 156 | + - normalized into absolute one |
| 157 | + """ |
| 158 | + root_path = str(tmpdir) |
| 159 | + |
| 160 | + invalid_roots = ['/invalid/root', '../baz'] |
| 161 | + source_roots = ['service/foo', 'service/bar'] + invalid_roots |
| 162 | + doc_root = source_roots[0] |
| 163 | + |
| 164 | + if metafile: |
| 165 | + dirname = os.path.dirname(metafile) |
| 166 | + if dirname: |
| 167 | + os.makedirs(os.path.join(root_path, dirname)) |
| 168 | + |
| 169 | + # configured by metafile at pyls startup |
| 170 | + with open(os.path.join(root_path, metafile), 'w+') as f: |
| 171 | + f.write('[pyls]\nsource_roots=\n %s\n' % |
| 172 | + ',\n '.join(_make_paths_dir_relative(source_roots, dirname))) |
| 173 | + |
| 174 | + pyls = PythonLanguageServer(StringIO, StringIO) |
| 175 | + pyls.m_initialize( |
| 176 | + processId=1, |
| 177 | + rootUri=uris.from_fs_path(root_path), |
| 178 | + initializationOptions={} |
| 179 | + ) |
| 180 | + |
| 181 | + # put new document under ROOT/service/foo |
| 182 | + test_uri = uris.from_fs_path(os.path.join(root_path, doc_root, 'hello/test.py')) |
| 183 | + pyls.workspace.put_document(test_uri, 'assert true') |
| 184 | + test_doc = pyls.workspace.get_document(test_uri) |
| 185 | + |
| 186 | + # apply os.path.normcase() on paths below, because case-sensitive |
| 187 | + # comparison on Windows causes unintentional failure for case |
| 188 | + # instability around drive letter |
| 189 | + |
| 190 | + sys_path = [os.path.normcase(p) for p in test_doc.sys_path()] |
| 191 | + for raw_path in source_roots: |
| 192 | + full_path = os.path.normcase(os.path.join(root_path, raw_path)) |
| 193 | + if raw_path in invalid_roots: |
| 194 | + assert os.path.normpath(full_path) not in sys_path |
| 195 | + assert full_path not in sys_path # check for safety |
| 196 | + else: |
| 197 | + assert os.path.normpath(full_path) in sys_path |
| 198 | + |
| 199 | + |
| 200 | +@pytest.mark.parametrize('metafile', ['setup.cfg', 'tox.ini']) |
| 201 | +def test_pyls_config_readin(tmpdir, metafile): |
| 202 | + """Examine that pyls config in the workspace root is always read in. |
| 203 | +
|
| 204 | + This test creates two config files. One is created in the |
| 205 | + workspace root, and another is created in ascendant of the target |
| 206 | + document. Only the former has source_roots config. |
| 207 | +
|
| 208 | + Then, this test examines that the former is always read in, |
| 209 | + regardless of existence of the latter, by checking source_roots |
| 210 | + config. |
| 211 | + """ |
| 212 | + root_path = str(tmpdir) |
| 213 | + |
| 214 | + source_roots = ['service/foo', 'service/bar'] |
| 215 | + |
| 216 | + with open(os.path.join(root_path, metafile), 'w+') as f: |
| 217 | + f.write('[pyls]\nsource_roots=\n %s\n' % |
| 218 | + ',\n '.join(source_roots)) |
| 219 | + |
| 220 | + doc_root = source_roots[0] |
| 221 | + |
| 222 | + os.makedirs(os.path.join(root_path, doc_root)) |
| 223 | + with open(os.path.join(root_path, doc_root, metafile), 'w+') as f: |
| 224 | + f.write('\n') |
| 225 | + |
| 226 | + pyls = PythonLanguageServer(StringIO, StringIO) |
| 227 | + pyls.m_initialize( |
| 228 | + processId=1, |
| 229 | + rootUri=uris.from_fs_path(root_path), |
| 230 | + initializationOptions={} |
| 231 | + ) |
| 232 | + |
| 233 | + # put new document under root/service/foo |
| 234 | + test_uri = uris.from_fs_path(os.path.join(root_path, doc_root, 'hello/test.py')) |
| 235 | + pyls.workspace.put_document(test_uri, 'assert True') |
| 236 | + test_doc = pyls.workspace.get_document(test_uri) |
| 237 | + |
| 238 | + # apply os.path.normcase() on paths below, because case-sensitive |
| 239 | + # comparison on Windows causes unintentional failure for case |
| 240 | + # instability around drive letter |
| 241 | + |
| 242 | + sys_path = [os.path.normcase(p) for p in test_doc.sys_path()] |
| 243 | + for raw_path in source_roots: |
| 244 | + full_path = os.path.normcase(os.path.join(root_path, raw_path)) |
| 245 | + assert os.path.normpath(full_path) in sys_path |
0 commit comments