Skip to content

Commit ba2aa6a

Browse files
committed
Add tests for pip's vcs module from pip
WARNING: tests will fail on this commit. Next commit will fix import paths and remove unnecessary stuff for the tests to work. File structure has been modified from pip, below is the mapping of fetchcode to pip. Files were copied without any modifications in this commit. Paths from respective repositories roots: { "tests/conftest.py":"tests/conftest.py", "tests/test_vcs_pip_bazaar.py":"tests/functional/test_vcs_bazaar.py", "tests/test_vcs_pip_git.py":"tests/functional/test_vcs_git.py", "tests/test_vcs_pip_mercurial.py":"tests/functional/test_vcs_mercurial.py", "tests/test_vcs_pip.py_subversion":"tests/functional/test_vcs_subversion.py", "tests/test_vcs_pip.py":"tests/unit/test_vcs.py", "tests/test_vcs_pip_mercurial_unit.py":"tests/unit/test_vcs.py", "tests/lib/__init__.py":"tests/lib/__init_.py", "tests/lib/git_submodule_helpers.py":"tests/lib/git_submodule_helpers.py", "tests/lib/local_repos.py":"tests/lib/local_repos.py", "tests/lib/path.py":"tests/lib/path.py", } It has been agreed with @pombredanne & @TG1999 that history from pip will be rebased on fetchcode by @pombredanne (thanks!). It will be done only for the files that are of concern to fetchcode. I'm leaving this commit without SoB intentionally, as this is not my work, but that of the many pip's authors: https://github.com/pypa/pip/blob/21.2.4/AUTHORS.txt License of pip: MIT (https://pypi.org/project/pip/) add conftest Signed-off-by: Alexander Mazuruk <a.mazuruk@samsung.com>
1 parent 60c720f commit ba2aa6a

12 files changed

+3205
-0
lines changed

tests/conftest.py

Lines changed: 570 additions & 0 deletions
Large diffs are not rendered by default.

tests/lib/__init__.py

Lines changed: 1226 additions & 0 deletions
Large diffs are not rendered by default.

tests/lib/compat.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import contextlib
2+
from typing import Iterator
3+
4+
5+
@contextlib.contextmanager
6+
def nullcontext():
7+
# type: () -> Iterator[None]
8+
"""
9+
Context manager that does no additional processing.
10+
11+
Used as a stand-in for a normal context manager, when a particular block of
12+
code is only sometimes used with a normal context manager:
13+
14+
cm = optional_cm if condition else nullcontext()
15+
with cm:
16+
# Perform operation, using optional_cm if condition is True
17+
18+
TODO: Replace with contextlib.nullcontext after dropping Python 3.6
19+
support.
20+
"""
21+
yield

tests/lib/git_submodule_helpers.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import textwrap
2+
3+
from tests.lib import _create_main_file, _git_commit
4+
5+
6+
def _create_test_package_submodule(env):
7+
env.scratch_path.joinpath("version_pkg_submodule").mkdir()
8+
submodule_path = env.scratch_path / "version_pkg_submodule"
9+
env.run("touch", "testfile", cwd=submodule_path)
10+
env.run("git", "init", cwd=submodule_path)
11+
env.run("git", "add", ".", cwd=submodule_path)
12+
_git_commit(env, submodule_path, message="initial version / submodule")
13+
14+
return submodule_path
15+
16+
17+
def _change_test_package_submodule(env, submodule_path):
18+
submodule_path.joinpath("testfile").write_text("this is a changed file")
19+
submodule_path.joinpath("testfile2").write_text("this is an added file")
20+
env.run("git", "add", ".", cwd=submodule_path)
21+
_git_commit(env, submodule_path, message="submodule change")
22+
23+
24+
def _pull_in_submodule_changes_to_module(env, module_path, rel_path):
25+
"""
26+
Args:
27+
rel_path: the location of the submodule relative to the superproject.
28+
"""
29+
submodule_path = module_path / rel_path
30+
env.run("git", "pull", "-q", "origin", "master", cwd=submodule_path)
31+
# Pass -a to stage the submodule changes that were just pulled in.
32+
_git_commit(env, module_path, message="submodule change", stage_modified=True)
33+
34+
35+
def _create_test_package_with_submodule(env, rel_path):
36+
"""
37+
Args:
38+
rel_path: the location of the submodule relative to the superproject.
39+
"""
40+
env.scratch_path.joinpath("version_pkg").mkdir()
41+
version_pkg_path = env.scratch_path / "version_pkg"
42+
version_pkg_path.joinpath("testpkg").mkdir()
43+
pkg_path = version_pkg_path / "testpkg"
44+
45+
pkg_path.joinpath("__init__.py").write_text("# hello there")
46+
_create_main_file(pkg_path, name="version_pkg", output="0.1")
47+
version_pkg_path.joinpath("setup.py").write_text(
48+
textwrap.dedent(
49+
"""\
50+
from setuptools import setup, find_packages
51+
setup(name='version_pkg',
52+
version='0.1',
53+
packages=find_packages(),
54+
)
55+
"""
56+
)
57+
)
58+
env.run("git", "init", cwd=version_pkg_path)
59+
env.run("git", "add", ".", cwd=version_pkg_path)
60+
_git_commit(env, version_pkg_path, message="initial version")
61+
62+
submodule_path = _create_test_package_submodule(env)
63+
64+
env.run(
65+
"git",
66+
"submodule",
67+
"add",
68+
submodule_path,
69+
rel_path,
70+
cwd=version_pkg_path,
71+
)
72+
_git_commit(env, version_pkg_path, message="initial version w submodule")
73+
74+
return version_pkg_path, submodule_path

tests/lib/local_repos.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import os
2+
import subprocess
3+
import urllib.request
4+
5+
from pip._internal.utils.misc import hide_url
6+
from pip._internal.vcs import vcs
7+
from tests.lib import path_to_url
8+
from tests.lib.path import Path
9+
10+
11+
def _create_svn_initools_repo(initools_dir):
12+
"""
13+
Create the SVN INITools repo.
14+
"""
15+
directory = os.path.dirname(initools_dir)
16+
subprocess.check_call("svnadmin create INITools".split(), cwd=directory)
17+
18+
filename, _ = urllib.request.urlretrieve(
19+
"http://bitbucket.org/hltbra/pip-initools-dump/raw/8b55c908a320/"
20+
"INITools_modified.dump"
21+
)
22+
with open(filename) as dump:
23+
subprocess.check_call(
24+
["svnadmin", "load", initools_dir],
25+
stdin=dump,
26+
stdout=subprocess.DEVNULL,
27+
)
28+
os.remove(filename)
29+
30+
31+
def local_checkout(
32+
remote_repo, # type: str
33+
temp_path, # type: Path
34+
):
35+
# type: (...) -> str
36+
"""
37+
:param temp_path: the return value of the tmpdir fixture, which is a
38+
temp directory Path object unique to each test function invocation,
39+
created as a sub directory of the base temp directory.
40+
"""
41+
assert "+" in remote_repo
42+
vcs_name = remote_repo.split("+", 1)[0]
43+
repository_name = os.path.basename(remote_repo)
44+
45+
directory = temp_path.joinpath("cache")
46+
repo_url_path = os.path.join(directory, repository_name)
47+
assert not os.path.exists(repo_url_path)
48+
49+
if not os.path.exists(directory):
50+
os.mkdir(directory)
51+
52+
if vcs_name == "svn":
53+
assert repository_name == "INITools"
54+
_create_svn_initools_repo(repo_url_path)
55+
repo_url_path = os.path.join(repo_url_path, "trunk")
56+
else:
57+
vcs_backend = vcs.get_backend(vcs_name)
58+
vcs_backend.obtain(repo_url_path, url=hide_url(remote_repo))
59+
60+
return "{}+{}".format(vcs_name, path_to_url(repo_url_path))
61+
62+
63+
def local_repo(remote_repo, temp_path):
64+
return local_checkout(remote_repo, temp_path).split("+", 1)[1]

tests/lib/path.py

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
# flake8: noqa
2+
# Author: Aziz Köksal
3+
import glob
4+
import os
5+
6+
try:
7+
from os import supports_fd
8+
except ImportError:
9+
supports_fd = set()
10+
11+
12+
class Path(str):
13+
"""
14+
Models a path in an object oriented way.
15+
"""
16+
17+
# File system path separator: '/' or '\'.
18+
sep = os.sep
19+
20+
# Separator in the PATH environment variable.
21+
pathsep = os.pathsep
22+
23+
def __new__(cls, *paths):
24+
if len(paths):
25+
return super().__new__(cls, os.path.join(*paths))
26+
return super().__new__(cls)
27+
28+
def __div__(self, path):
29+
"""
30+
Joins this path with another path.
31+
32+
>>> path_obj / 'bc.d'
33+
>>> path_obj / path_obj2
34+
"""
35+
return Path(self, path)
36+
37+
__truediv__ = __div__
38+
39+
def __rdiv__(self, path):
40+
"""
41+
Joins this path with another path.
42+
43+
>>> "/home/a" / path_obj
44+
"""
45+
return Path(path, self)
46+
47+
__rtruediv__ = __rdiv__
48+
49+
def __idiv__(self, path):
50+
"""
51+
Like __div__ but also assigns to the variable.
52+
53+
>>> path_obj /= 'bc.d'
54+
"""
55+
return Path(self, path)
56+
57+
__itruediv__ = __idiv__
58+
59+
def __add__(self, path):
60+
"""
61+
>>> Path('/home/a') + 'bc.d'
62+
'/home/abc.d'
63+
"""
64+
return Path(str(self) + path)
65+
66+
def __radd__(self, path):
67+
"""
68+
>>> '/home/a' + Path('bc.d')
69+
'/home/abc.d'
70+
"""
71+
return Path(path + str(self))
72+
73+
def __repr__(self):
74+
return "Path({inner})".format(inner=str.__repr__(self))
75+
76+
@property
77+
def name(self):
78+
"""
79+
'/home/a/bc.d' -> 'bc.d'
80+
"""
81+
return os.path.basename(self)
82+
83+
@property
84+
def stem(self):
85+
"""
86+
'/home/a/bc.d' -> 'bc'
87+
"""
88+
return Path(os.path.splitext(self)[0]).name
89+
90+
@property
91+
def suffix(self):
92+
"""
93+
'/home/a/bc.d' -> '.d'
94+
"""
95+
return Path(os.path.splitext(self)[1])
96+
97+
def resolve(self):
98+
"""
99+
Resolves symbolic links.
100+
"""
101+
return Path(os.path.realpath(self))
102+
103+
@property
104+
def parent(self):
105+
"""
106+
Returns the parent directory of this path.
107+
108+
'/home/a/bc.d' -> '/home/a'
109+
'/home/a/' -> '/home/a'
110+
'/home/a' -> '/home'
111+
"""
112+
return Path(os.path.dirname(self))
113+
114+
def exists(self):
115+
"""
116+
Returns True if the path exists.
117+
"""
118+
return os.path.exists(self)
119+
120+
def mkdir(self, mode=0x1FF, exist_ok=False, parents=False): # 0o777
121+
"""
122+
Creates a directory, if it doesn't exist already.
123+
124+
:param parents: Whether to create parent directories.
125+
"""
126+
127+
maker_func = os.makedirs if parents else os.mkdir
128+
try:
129+
maker_func(self, mode)
130+
except OSError:
131+
if not exist_ok or not os.path.isdir(self):
132+
raise
133+
134+
def unlink(self):
135+
"""
136+
Removes a file.
137+
"""
138+
return os.remove(self)
139+
140+
def rmdir(self):
141+
"""
142+
Removes a directory.
143+
"""
144+
return os.rmdir(self)
145+
146+
def rename(self, to):
147+
"""
148+
Renames a file or directory. May throw an OSError.
149+
"""
150+
return os.rename(self, to)
151+
152+
def glob(self, pattern):
153+
return (Path(i) for i in glob.iglob(self.joinpath(pattern)))
154+
155+
def joinpath(self, *parts):
156+
return Path(self, *parts)
157+
158+
# TODO: Remove after removing inheritance from str.
159+
def join(self, *parts):
160+
raise RuntimeError("Path.join is invalid, use joinpath instead.")
161+
162+
def read_bytes(self):
163+
# type: () -> bytes
164+
with open(self, "rb") as fp:
165+
return fp.read()
166+
167+
def write_bytes(self, content):
168+
# type: (bytes) -> None
169+
with open(self, "wb") as f:
170+
f.write(content)
171+
172+
def read_text(self):
173+
with open(self, "r") as fp:
174+
return fp.read()
175+
176+
def write_text(self, content):
177+
with open(self, "w") as fp:
178+
fp.write(content)
179+
180+
def touch(self):
181+
with open(self, "a") as fp:
182+
path = fp.fileno() if os.utime in supports_fd else self
183+
os.utime(path, None) # times is not optional on Python 2.7
184+
185+
def symlink_to(self, target):
186+
os.symlink(target, self)
187+
188+
def stat(self):
189+
return os.stat(self)
190+
191+
192+
curdir = Path(os.path.curdir)

0 commit comments

Comments
 (0)