|
| 1 | +""" |
| 2 | +Tests for Windows-flavoured pathlib.types._JoinablePath |
| 3 | +""" |
| 4 | + |
| 5 | +import os |
| 6 | +import unittest |
| 7 | + |
| 8 | +from pathlib import PureWindowsPath, WindowsPath |
| 9 | +from test.test_pathlib.support.lexical_path import LexicalWindowsPath |
| 10 | + |
| 11 | + |
| 12 | +class JoinTestBase: |
| 13 | + def test_join(self): |
| 14 | + P = self.cls |
| 15 | + p = P('C:/a/b') |
| 16 | + pp = p.joinpath('x/y') |
| 17 | + self.assertEqual(pp, P(r'C:/a/b\x/y')) |
| 18 | + pp = p.joinpath('/x/y') |
| 19 | + self.assertEqual(pp, P('C:/x/y')) |
| 20 | + # Joining with a different drive => the first path is ignored, even |
| 21 | + # if the second path is relative. |
| 22 | + pp = p.joinpath('D:x/y') |
| 23 | + self.assertEqual(pp, P('D:x/y')) |
| 24 | + pp = p.joinpath('D:/x/y') |
| 25 | + self.assertEqual(pp, P('D:/x/y')) |
| 26 | + pp = p.joinpath('//host/share/x/y') |
| 27 | + self.assertEqual(pp, P('//host/share/x/y')) |
| 28 | + # Joining with the same drive => the first path is appended to if |
| 29 | + # the second path is relative. |
| 30 | + pp = p.joinpath('c:x/y') |
| 31 | + self.assertEqual(pp, P(r'c:/a/b\x/y')) |
| 32 | + pp = p.joinpath('c:/x/y') |
| 33 | + self.assertEqual(pp, P('c:/x/y')) |
| 34 | + # Joining with files with NTFS data streams => the filename should |
| 35 | + # not be parsed as a drive letter |
| 36 | + pp = p.joinpath('./d:s') |
| 37 | + self.assertEqual(pp, P(r'C:/a/b\./d:s')) |
| 38 | + pp = p.joinpath('./dd:s') |
| 39 | + self.assertEqual(pp, P(r'C:/a/b\./dd:s')) |
| 40 | + pp = p.joinpath('E:d:s') |
| 41 | + self.assertEqual(pp, P('E:d:s')) |
| 42 | + # Joining onto a UNC path with no root |
| 43 | + pp = P('//').joinpath('server') |
| 44 | + self.assertEqual(pp, P('//server')) |
| 45 | + pp = P('//server').joinpath('share') |
| 46 | + self.assertEqual(pp, P(r'//server\share')) |
| 47 | + pp = P('//./BootPartition').joinpath('Windows') |
| 48 | + self.assertEqual(pp, P(r'//./BootPartition\Windows')) |
| 49 | + |
| 50 | + def test_div(self): |
| 51 | + # Basically the same as joinpath(). |
| 52 | + P = self.cls |
| 53 | + p = P('C:/a/b') |
| 54 | + self.assertEqual(p / 'x/y', P(r'C:/a/b\x/y')) |
| 55 | + self.assertEqual(p / 'x' / 'y', P(r'C:/a/b\x\y')) |
| 56 | + self.assertEqual(p / '/x/y', P('C:/x/y')) |
| 57 | + self.assertEqual(p / '/x' / 'y', P('C:/x\y')) |
| 58 | + # Joining with a different drive => the first path is ignored, even |
| 59 | + # if the second path is relative. |
| 60 | + self.assertEqual(p / 'D:x/y', P('D:x/y')) |
| 61 | + self.assertEqual(p / 'D:' / 'x/y', P('D:x/y')) |
| 62 | + self.assertEqual(p / 'D:/x/y', P('D:/x/y')) |
| 63 | + self.assertEqual(p / 'D:' / '/x/y', P('D:/x/y')) |
| 64 | + self.assertEqual(p / '//host/share/x/y', P('//host/share/x/y')) |
| 65 | + # Joining with the same drive => the first path is appended to if |
| 66 | + # the second path is relative. |
| 67 | + self.assertEqual(p / 'c:x/y', P(r'c:/a/b\x/y')) |
| 68 | + self.assertEqual(p / 'c:/x/y', P('c:/x/y')) |
| 69 | + # Joining with files with NTFS data streams => the filename should |
| 70 | + # not be parsed as a drive letter |
| 71 | + self.assertEqual(p / './d:s', P(r'C:/a/b\./d:s')) |
| 72 | + self.assertEqual(p / './dd:s', P(r'C:/a/b\./dd:s')) |
| 73 | + self.assertEqual(p / 'E:d:s', P('E:d:s')) |
| 74 | + |
| 75 | + def test_str(self): |
| 76 | + p = self.cls(r'a\b\c') |
| 77 | + self.assertEqual(str(p), 'a\\b\\c') |
| 78 | + p = self.cls(r'c:\a\b\c') |
| 79 | + self.assertEqual(str(p), 'c:\\a\\b\\c') |
| 80 | + p = self.cls('\\\\a\\b\\') |
| 81 | + self.assertEqual(str(p), '\\\\a\\b\\') |
| 82 | + p = self.cls(r'\\a\b\c') |
| 83 | + self.assertEqual(str(p), '\\\\a\\b\\c') |
| 84 | + p = self.cls(r'\\a\b\c\d') |
| 85 | + self.assertEqual(str(p), '\\\\a\\b\\c\\d') |
| 86 | + |
| 87 | + def test_parts(self): |
| 88 | + P = self.cls |
| 89 | + p = P(r'c:a\b') |
| 90 | + parts = p.parts |
| 91 | + self.assertEqual(parts, ('c:', 'a', 'b')) |
| 92 | + p = P(r'c:\a\b') |
| 93 | + parts = p.parts |
| 94 | + self.assertEqual(parts, ('c:\\', 'a', 'b')) |
| 95 | + p = P(r'\\a\b\c\d') |
| 96 | + parts = p.parts |
| 97 | + self.assertEqual(parts, ('\\\\a\\b\\', 'c', 'd')) |
| 98 | + |
| 99 | + def test_parent(self): |
| 100 | + # Anchored |
| 101 | + P = self.cls |
| 102 | + p = P('z:a/b/c') |
| 103 | + self.assertEqual(p.parent, P('z:a/b')) |
| 104 | + self.assertEqual(p.parent.parent, P('z:a')) |
| 105 | + self.assertEqual(p.parent.parent.parent, P('z:')) |
| 106 | + self.assertEqual(p.parent.parent.parent.parent, P('z:')) |
| 107 | + p = P('z:/a/b/c') |
| 108 | + self.assertEqual(p.parent, P('z:/a/b')) |
| 109 | + self.assertEqual(p.parent.parent, P('z:/a')) |
| 110 | + self.assertEqual(p.parent.parent.parent, P('z:/')) |
| 111 | + self.assertEqual(p.parent.parent.parent.parent, P('z:/')) |
| 112 | + p = P('//a/b/c/d') |
| 113 | + self.assertEqual(p.parent, P('//a/b/c')) |
| 114 | + self.assertEqual(p.parent.parent, P('//a/b/')) |
| 115 | + self.assertEqual(p.parent.parent.parent, P('//a/b/')) |
| 116 | + |
| 117 | + def test_parents(self): |
| 118 | + # Anchored |
| 119 | + P = self.cls |
| 120 | + p = P('z:a/b') |
| 121 | + par = p.parents |
| 122 | + self.assertEqual(len(par), 2) |
| 123 | + self.assertEqual(par[0], P('z:a')) |
| 124 | + self.assertEqual(par[1], P('z:')) |
| 125 | + self.assertEqual(par[0:1], (P('z:a'),)) |
| 126 | + self.assertEqual(par[:-1], (P('z:a'),)) |
| 127 | + self.assertEqual(par[:2], (P('z:a'), P('z:'))) |
| 128 | + self.assertEqual(par[1:], (P('z:'),)) |
| 129 | + self.assertEqual(par[::2], (P('z:a'),)) |
| 130 | + self.assertEqual(par[::-1], (P('z:'), P('z:a'))) |
| 131 | + self.assertEqual(list(par), [P('z:a'), P('z:')]) |
| 132 | + with self.assertRaises(IndexError): |
| 133 | + par[2] |
| 134 | + p = P('z:/a/b') |
| 135 | + par = p.parents |
| 136 | + self.assertEqual(len(par), 2) |
| 137 | + self.assertEqual(par[0], P('z:/a')) |
| 138 | + self.assertEqual(par[1], P('z:/')) |
| 139 | + self.assertEqual(par[0:1], (P('z:/a'),)) |
| 140 | + self.assertEqual(par[0:-1], (P('z:/a'),)) |
| 141 | + self.assertEqual(par[:2], (P('z:/a'), P('z:/'))) |
| 142 | + self.assertEqual(par[1:], (P('z:/'),)) |
| 143 | + self.assertEqual(par[::2], (P('z:/a'),)) |
| 144 | + self.assertEqual(par[::-1], (P('z:/'), P('z:/a'),)) |
| 145 | + self.assertEqual(list(par), [P('z:/a'), P('z:/')]) |
| 146 | + with self.assertRaises(IndexError): |
| 147 | + par[2] |
| 148 | + p = P('//a/b/c/d') |
| 149 | + par = p.parents |
| 150 | + self.assertEqual(len(par), 2) |
| 151 | + self.assertEqual(par[0], P('//a/b/c')) |
| 152 | + self.assertEqual(par[1], P('//a/b/')) |
| 153 | + self.assertEqual(par[0:1], (P('//a/b/c'),)) |
| 154 | + self.assertEqual(par[0:-1], (P('//a/b/c'),)) |
| 155 | + self.assertEqual(par[:2], (P('//a/b/c'), P('//a/b/'))) |
| 156 | + self.assertEqual(par[1:], (P('//a/b/'),)) |
| 157 | + self.assertEqual(par[::2], (P('//a/b/c'),)) |
| 158 | + self.assertEqual(par[::-1], (P('//a/b/'), P('//a/b/c'))) |
| 159 | + self.assertEqual(list(par), [P('//a/b/c'), P('//a/b/')]) |
| 160 | + with self.assertRaises(IndexError): |
| 161 | + par[2] |
| 162 | + |
| 163 | + def test_anchor(self): |
| 164 | + P = self.cls |
| 165 | + self.assertEqual(P('c:').anchor, 'c:') |
| 166 | + self.assertEqual(P('c:a/b').anchor, 'c:') |
| 167 | + self.assertEqual(P('c:\\').anchor, 'c:\\') |
| 168 | + self.assertEqual(P('c:\\a\\b\\').anchor, 'c:\\') |
| 169 | + self.assertEqual(P('\\\\a\\b\\').anchor, '\\\\a\\b\\') |
| 170 | + self.assertEqual(P('\\\\a\\b\\c\\d').anchor, '\\\\a\\b\\') |
| 171 | + |
| 172 | + def test_name(self): |
| 173 | + P = self.cls |
| 174 | + self.assertEqual(P('c:').name, '') |
| 175 | + self.assertEqual(P('c:/').name, '') |
| 176 | + self.assertEqual(P('c:a/b').name, 'b') |
| 177 | + self.assertEqual(P('c:/a/b').name, 'b') |
| 178 | + self.assertEqual(P('c:a/b.py').name, 'b.py') |
| 179 | + self.assertEqual(P('c:/a/b.py').name, 'b.py') |
| 180 | + self.assertEqual(P('//My.py/Share.php').name, '') |
| 181 | + self.assertEqual(P('//My.py/Share.php/a/b').name, 'b') |
| 182 | + |
| 183 | + def test_stem(self): |
| 184 | + P = self.cls |
| 185 | + self.assertEqual(P('c:').stem, '') |
| 186 | + self.assertEqual(P('c:..').stem, '..') |
| 187 | + self.assertEqual(P('c:/').stem, '') |
| 188 | + self.assertEqual(P('c:a/b').stem, 'b') |
| 189 | + self.assertEqual(P('c:a/b.py').stem, 'b') |
| 190 | + self.assertEqual(P('c:a/.hgrc').stem, '.hgrc') |
| 191 | + self.assertEqual(P('c:a/.hg.rc').stem, '.hg') |
| 192 | + self.assertEqual(P('c:a/b.tar.gz').stem, 'b.tar') |
| 193 | + self.assertEqual(P('c:a/trailing.dot.').stem, 'trailing.dot') |
| 194 | + |
| 195 | + def test_suffix(self): |
| 196 | + P = self.cls |
| 197 | + self.assertEqual(P('c:').suffix, '') |
| 198 | + self.assertEqual(P('c:/').suffix, '') |
| 199 | + self.assertEqual(P('c:a/b').suffix, '') |
| 200 | + self.assertEqual(P('c:/a/b').suffix, '') |
| 201 | + self.assertEqual(P('c:a/b.py').suffix, '.py') |
| 202 | + self.assertEqual(P('c:/a/b.py').suffix, '.py') |
| 203 | + self.assertEqual(P('c:a/.hgrc').suffix, '') |
| 204 | + self.assertEqual(P('c:/a/.hgrc').suffix, '') |
| 205 | + self.assertEqual(P('c:a/.hg.rc').suffix, '.rc') |
| 206 | + self.assertEqual(P('c:/a/.hg.rc').suffix, '.rc') |
| 207 | + self.assertEqual(P('c:a/b.tar.gz').suffix, '.gz') |
| 208 | + self.assertEqual(P('c:/a/b.tar.gz').suffix, '.gz') |
| 209 | + self.assertEqual(P('c:a/trailing.dot.').suffix, '.') |
| 210 | + self.assertEqual(P('c:/a/trailing.dot.').suffix, '.') |
| 211 | + self.assertEqual(P('//My.py/Share.php').suffix, '') |
| 212 | + self.assertEqual(P('//My.py/Share.php/a/b').suffix, '') |
| 213 | + |
| 214 | + def test_suffixes(self): |
| 215 | + P = self.cls |
| 216 | + self.assertEqual(P('c:').suffixes, []) |
| 217 | + self.assertEqual(P('c:/').suffixes, []) |
| 218 | + self.assertEqual(P('c:a/b').suffixes, []) |
| 219 | + self.assertEqual(P('c:/a/b').suffixes, []) |
| 220 | + self.assertEqual(P('c:a/b.py').suffixes, ['.py']) |
| 221 | + self.assertEqual(P('c:/a/b.py').suffixes, ['.py']) |
| 222 | + self.assertEqual(P('c:a/.hgrc').suffixes, []) |
| 223 | + self.assertEqual(P('c:/a/.hgrc').suffixes, []) |
| 224 | + self.assertEqual(P('c:a/.hg.rc').suffixes, ['.rc']) |
| 225 | + self.assertEqual(P('c:/a/.hg.rc').suffixes, ['.rc']) |
| 226 | + self.assertEqual(P('c:a/b.tar.gz').suffixes, ['.tar', '.gz']) |
| 227 | + self.assertEqual(P('c:/a/b.tar.gz').suffixes, ['.tar', '.gz']) |
| 228 | + self.assertEqual(P('//My.py/Share.php').suffixes, []) |
| 229 | + self.assertEqual(P('//My.py/Share.php/a/b').suffixes, []) |
| 230 | + self.assertEqual(P('c:a/trailing.dot.').suffixes, ['.dot', '.']) |
| 231 | + self.assertEqual(P('c:/a/trailing.dot.').suffixes, ['.dot', '.']) |
| 232 | + |
| 233 | + def test_with_name(self): |
| 234 | + P = self.cls |
| 235 | + self.assertEqual(P(r'c:a\b').with_name('d.xml'), P(r'c:a\d.xml')) |
| 236 | + self.assertEqual(P(r'c:\a\b').with_name('d.xml'), P(r'c:\a\d.xml')) |
| 237 | + self.assertEqual(P(r'c:a\Dot ending.').with_name('d.xml'), P(r'c:a\d.xml')) |
| 238 | + self.assertEqual(P(r'c:\a\Dot ending.').with_name('d.xml'), P(r'c:\a\d.xml')) |
| 239 | + self.assertRaises(ValueError, P(r'c:a\b').with_name, r'd:\e') |
| 240 | + self.assertRaises(ValueError, P(r'c:a\b').with_name, r'\\My\Share') |
| 241 | + |
| 242 | + def test_with_stem(self): |
| 243 | + P = self.cls |
| 244 | + self.assertEqual(P('c:a/b').with_stem('d'), P('c:a/d')) |
| 245 | + self.assertEqual(P('c:/a/b').with_stem('d'), P('c:/a/d')) |
| 246 | + self.assertEqual(P('c:a/Dot ending.').with_stem('d'), P('c:a/d.')) |
| 247 | + self.assertEqual(P('c:/a/Dot ending.').with_stem('d'), P('c:/a/d.')) |
| 248 | + self.assertRaises(ValueError, P('c:a/b').with_stem, 'd:/e') |
| 249 | + self.assertRaises(ValueError, P('c:a/b').with_stem, '//My/Share') |
| 250 | + |
| 251 | + def test_with_suffix(self): |
| 252 | + P = self.cls |
| 253 | + self.assertEqual(P('c:a/b').with_suffix('.gz'), P('c:a/b.gz')) |
| 254 | + self.assertEqual(P('c:/a/b').with_suffix('.gz'), P('c:/a/b.gz')) |
| 255 | + self.assertEqual(P('c:a/b.py').with_suffix('.gz'), P('c:a/b.gz')) |
| 256 | + self.assertEqual(P('c:/a/b.py').with_suffix('.gz'), P('c:/a/b.gz')) |
| 257 | + # Path doesn't have a "filename" component. |
| 258 | + self.assertRaises(ValueError, P('').with_suffix, '.gz') |
| 259 | + self.assertRaises(ValueError, P('/').with_suffix, '.gz') |
| 260 | + self.assertRaises(ValueError, P('//My/Share').with_suffix, '.gz') |
| 261 | + # Invalid suffix. |
| 262 | + self.assertRaises(ValueError, P('c:a/b').with_suffix, 'gz') |
| 263 | + self.assertRaises(ValueError, P('c:a/b').with_suffix, '/') |
| 264 | + self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\') |
| 265 | + self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:') |
| 266 | + self.assertRaises(ValueError, P('c:a/b').with_suffix, '/.gz') |
| 267 | + self.assertRaises(ValueError, P('c:a/b').with_suffix, '\\.gz') |
| 268 | + self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c:.gz') |
| 269 | + self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c/d') |
| 270 | + self.assertRaises(ValueError, P('c:a/b').with_suffix, 'c\\d') |
| 271 | + self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c/d') |
| 272 | + self.assertRaises(ValueError, P('c:a/b').with_suffix, '.c\\d') |
| 273 | + self.assertRaises(TypeError, P('c:a/b').with_suffix, None) |
| 274 | + |
| 275 | + |
| 276 | +class LexicalWindowsPathJoinTest(JoinTestBase, unittest.TestCase): |
| 277 | + cls = LexicalWindowsPath |
| 278 | + |
| 279 | + |
| 280 | +class PureWindowsPathJoinTest(JoinTestBase, unittest.TestCase): |
| 281 | + cls = PureWindowsPath |
| 282 | + |
| 283 | + |
| 284 | +if os.name == 'nt': |
| 285 | + class WindowsPathJoinTest(JoinTestBase, unittest.TestCase): |
| 286 | + cls = WindowsPath |
| 287 | + |
| 288 | + |
| 289 | +if __name__ == "__main__": |
| 290 | + unittest.main() |
0 commit comments