8 from . import PexpectTestCase
13 class TestCaseWhich(PexpectTestCase.PexpectTestCase):
14 " Tests for pexpect.which(). "
16 def test_which_finds_ls(self):
17 " which() can find ls(1). "
18 exercise = pexpect.which("ls")
19 assert exercise is not None
20 assert exercise.startswith('/')
22 def test_os_defpath_which(self):
23 " which() finds an executable in $PATH and returns its abspath. "
25 bin_dir = tempfile.mkdtemp()
26 bin_path = os.path.join(bin_dir, fname)
27 save_path = os.environ['PATH']
28 save_defpath = os.defpath
32 os.environ['PATH'] = ''
34 with open(bin_path, 'w') as fp:
37 # given non-executable,
38 os.chmod(bin_path, 0o400)
40 # exercise absolute and relative,
41 assert pexpect.which(bin_path) is None
42 assert pexpect.which(fname) is None
45 os.chmod(bin_path, 0o700)
47 # exercise absolute and relative,
48 assert pexpect.which(bin_path) == bin_path
49 assert pexpect.which(fname) == bin_path
53 os.environ['PATH'] = save_path
54 os.defpath = save_defpath
56 # destroy scratch files and folders,
57 if os.path.exists(bin_path):
59 if os.path.exists(bin_dir):
62 def test_path_search_which(self):
63 " which() finds an executable in $PATH and returns its abspath. "
65 bin_dir = tempfile.mkdtemp()
66 bin_path = os.path.join(bin_dir, fname)
67 save_path = os.environ['PATH']
70 os.environ['PATH'] = bin_dir
71 with open(bin_path, 'w') as fp:
74 # given non-executable,
75 os.chmod(bin_path, 0o400)
77 # exercise absolute and relative,
78 assert pexpect.which(bin_path) is None
79 assert pexpect.which(fname) is None
82 os.chmod(bin_path, 0o700)
84 # exercise absolute and relative,
85 assert pexpect.which(bin_path) == bin_path
86 assert pexpect.which(fname) == bin_path
90 os.environ['PATH'] = save_path
92 # destroy scratch files and folders,
93 if os.path.exists(bin_path):
95 if os.path.exists(bin_dir):
98 def test_which_follows_symlink(self):
99 " which() follows symlinks and returns its path. "
101 symname = 'extra-crispy'
102 bin_dir = tempfile.mkdtemp()
103 bin_path = os.path.join(bin_dir, fname)
104 sym_path = os.path.join(bin_dir, symname)
105 save_path = os.environ['PATH']
108 os.environ['PATH'] = bin_dir
109 with open(bin_path, 'w') as fp:
111 os.chmod(bin_path, 0o400)
112 os.symlink(bin_path, sym_path)
114 # should not be found because symlink points to non-executable
115 assert pexpect.which(symname) is None
117 # but now it should -- because it is executable
118 os.chmod(bin_path, 0o700)
119 assert pexpect.which(symname) == sym_path
123 os.environ['PATH'] = save_path
125 # destroy scratch files, symlinks, and folders,
126 if os.path.exists(sym_path):
128 if os.path.exists(bin_path):
130 if os.path.exists(bin_dir):
133 def test_which_should_not_match_folders(self):
134 " Which does not match folders, even though they are executable. "
135 # make up a path and insert a folder that is 'executable', a naive
136 # implementation might match (previously pexpect versions 3.2 and
137 # sh versions 1.0.8, reported by @lcm337.)
139 bin_dir = tempfile.mkdtemp()
140 bin_dir2 = os.path.join(bin_dir, fname)
141 save_path = os.environ['PATH']
143 os.environ['PATH'] = bin_dir
144 os.mkdir(bin_dir2, 0o755)
145 # should not be found because it is not executable *file*,
146 # but rather, has the executable bit set, as a good folder
147 # should -- it should not be returned because it fails isdir()
148 exercise = pexpect.which(fname)
149 assert exercise is None
153 os.environ['PATH'] = save_path
154 # destroy scratch folders,
155 for _dir in (bin_dir2, bin_dir,):
156 if os.path.exists(_dir):
159 def test_which_should_match_other_group_user(self):
160 " which() returns executables by other, group, and user ownership. "
161 # create an executable and test that it is found using which() for
162 # each of the 'other', 'group', and 'user' permission bits.
164 bin_dir = tempfile.mkdtemp()
165 bin_path = os.path.join(bin_dir, fname)
166 save_path = os.environ['PATH']
169 os.environ['PATH'] = bin_dir
171 # an interpreted script requires the ability to read,
172 # whereas a binary program requires only to be executable.
174 # to gain access to a binary program, we make a copy of
175 # the existing system program echo(1).
177 for pth in ('/bin/echo', '/usr/bin/echo'):
178 if os.path.exists(pth):
182 for pth in ('/bin/which', '/usr/bin/which'):
183 if os.path.exists(pth):
186 if not bin_echo or not bin_which:
187 pytest.skip('needs `echo` and `which` binaries')
188 shutil.copy(bin_echo, bin_path)
189 isroot = os.getuid() == 0
190 for should_match, mode in (
191 # note that although the file may have matching 'group' or
192 # 'other' executable permissions, it is *not* executable
193 # because the current uid is the owner of the file -- which
195 (False, 0o000), # ----------, no
196 (isroot, 0o001), # ---------x, no
197 (isroot, 0o010), # ------x---, no
198 (True, 0o100), # ---x------, yes
199 (False, 0o002), # --------w-, no
200 (False, 0o020), # -----w----, no
201 (False, 0o200), # --w-------, no
202 (isroot, 0o003), # --------wx, no
203 (isroot, 0o030), # -----wx---, no
204 (True, 0o300), # --wx------, yes
205 (False, 0o004), # -------r--, no
206 (False, 0o040), # ----r-----, no
207 (False, 0o400), # -r--------, no
208 (isroot, 0o005), # -------r-x, no
209 (isroot, 0o050), # ----r-x---, no
210 (True, 0o500), # -r-x------, yes
211 (False, 0o006), # -------rw-, no
212 (False, 0o060), # ----rw----, no
213 (False, 0o600), # -rw-------, no
214 (isroot, 0o007), # -------rwx, no
215 (isroot, 0o070), # ----rwx---, no
216 (True, 0o700), # -rwx------, yes
217 (isroot, 0o4001), # ---S-----x, no
218 (isroot, 0o4010), # ---S--x---, no
219 (True, 0o4100), # ---s------, yes
220 (isroot, 0o4003), # ---S----wx, no
221 (isroot, 0o4030), # ---S-wx---, no
222 (True, 0o4300), # --ws------, yes
223 (isroot, 0o2001), # ------S--x, no
224 (isroot, 0o2010), # ------s---, no
225 (True, 0o2100), # ---x--S---, yes
228 mode_str = '{0:0>4o}'.format(mode)
231 os.chmod(bin_path, mode)
233 # exercise whether we may execute
236 subprocess.Popen(fname).wait() == 0
237 except OSError as err:
238 if err.errno != errno.EACCES:
243 assert should_match == can_execute, (
244 should_match, can_execute, mode_str)
246 # exercise whether which(1) would match
247 proc = subprocess.Popen((bin_which, fname),
248 env={'PATH': bin_dir},
249 stdout=subprocess.PIPE)
250 bin_which_match = bool(not proc.wait())
251 assert should_match == bin_which_match, (
252 should_match, bin_which_match, mode_str)
254 # finally, exercise pexpect's which(1) matches
256 pexpect_match = bool(pexpect.which(fname))
258 assert should_match == pexpect_match == bin_which_match, (
259 should_match, pexpect_match, bin_which_match, mode_str)
263 os.environ['PATH'] = save_path
265 # destroy scratch files and folders,
266 if os.path.exists(bin_path):
268 if os.path.exists(bin_dir):