tos.nim 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. discard """
  2. output: '''
  3. All:
  4. __really_obscure_dir_name/are.x
  5. __really_obscure_dir_name/created
  6. __really_obscure_dir_name/dirs
  7. __really_obscure_dir_name/files.q
  8. __really_obscure_dir_name/some
  9. __really_obscure_dir_name/test
  10. __really_obscure_dir_name/testing.r
  11. __really_obscure_dir_name/these.txt
  12. Files:
  13. __really_obscure_dir_name/are.x
  14. __really_obscure_dir_name/files.q
  15. __really_obscure_dir_name/testing.r
  16. __really_obscure_dir_name/these.txt
  17. Dirs:
  18. __really_obscure_dir_name/created
  19. __really_obscure_dir_name/dirs
  20. __really_obscure_dir_name/some
  21. __really_obscure_dir_name/test
  22. Raises
  23. Raises
  24. '''
  25. matrix: "--mm:refc; --mm:orc"
  26. joinable: false
  27. """
  28. # test os path creation, iteration, and deletion
  29. from stdtest/specialpaths import buildDir
  30. import std/[syncio, assertions, osproc, os, strutils, pathnorm]
  31. block fileOperations:
  32. let files = @["these.txt", "are.x", "testing.r", "files.q"]
  33. let dirs = @["some", "created", "test", "dirs"]
  34. let dname = "__really_obscure_dir_name"
  35. createDir(dname)
  36. doAssert dirExists(dname)
  37. block: # copyFile, copyFileToDir
  38. doAssertRaises(OSError): copyFile(dname/"nonexistent.txt", dname/"nonexistent.txt")
  39. let fname = "D20201009T112235"
  40. let fname2 = "D20201009T112235.2"
  41. let str = "foo1\0foo2\nfoo3\0"
  42. let file = dname/fname
  43. let file2 = dname/fname2
  44. writeFile(file, str)
  45. doAssert readFile(file) == str
  46. let sub = "sub"
  47. doAssertRaises(OSError): copyFile(file, dname/sub/fname2)
  48. doAssertRaises(OSError): copyFileToDir(file, dname/sub)
  49. doAssertRaises(ValueError): copyFileToDir(file, "")
  50. copyFile(file, file2)
  51. doAssert fileExists(file2)
  52. doAssert readFile(file2) == str
  53. createDir(dname/sub)
  54. copyFileToDir(file, dname/sub)
  55. doAssert fileExists(dname/sub/fname)
  56. removeDir(dname/sub)
  57. doAssert not dirExists(dname/sub)
  58. removeFile(file)
  59. removeFile(file2)
  60. # Test creating files and dirs
  61. for dir in dirs:
  62. createDir(dname/dir)
  63. doAssert dirExists(dname/dir)
  64. for file in files:
  65. let fh = open(dname/file, fmReadWrite)
  66. fh.close()
  67. doAssert fileExists(dname/file)
  68. echo "All:"
  69. template norm(x): untyped =
  70. (when defined(windows): x.replace('\\', '/') else: x)
  71. for path in walkPattern(dname/"*"):
  72. echo path.norm
  73. echo "Files:"
  74. for path in walkFiles(dname/"*"):
  75. echo path.norm
  76. echo "Dirs:"
  77. for path in walkDirs(dname/"*"):
  78. echo path.norm
  79. # Test removal of files dirs
  80. for dir in dirs:
  81. removeDir(dname/dir)
  82. doAssert: not dirExists(dname/dir)
  83. for file in files:
  84. removeFile(dname/file)
  85. doAssert: not fileExists(dname/file)
  86. removeDir(dname)
  87. doAssert: not dirExists(dname)
  88. # createDir should create recursive directories
  89. createDir(dirs[0] / dirs[1])
  90. doAssert dirExists(dirs[0] / dirs[1]) # true
  91. removeDir(dirs[0])
  92. # createDir should properly handle trailing separator
  93. createDir(dname / "")
  94. doAssert dirExists(dname) # true
  95. removeDir(dname)
  96. # createDir should raise IOError if the path exists
  97. # and is not a directory
  98. open(dname, fmWrite).close
  99. try:
  100. createDir(dname)
  101. except IOError:
  102. echo "Raises"
  103. removeFile(dname)
  104. # removeFile should not remove directory
  105. createDir(dname)
  106. try:
  107. removeFile(dname)
  108. except OSError:
  109. echo "Raises"
  110. removeDir(dname)
  111. # test copyDir:
  112. createDir("a/b")
  113. open("a/b/file.txt", fmWrite).close
  114. createDir("a/b/c")
  115. open("a/b/c/fileC.txt", fmWrite).close
  116. copyDir("a", "../dest/a")
  117. removeDir("a")
  118. doAssert dirExists("../dest/a/b")
  119. doAssert fileExists("../dest/a/b/file.txt")
  120. doAssert fileExists("../dest/a/b/c/fileC.txt")
  121. removeDir("../dest")
  122. # test copyDir:
  123. # if separator at the end of a path
  124. createDir("a/b")
  125. open("a/file.txt", fmWrite).close
  126. copyDir("a/", "../dest/a/")
  127. removeDir("a")
  128. doAssert dirExists("../dest/a/b")
  129. doAssert fileExists("../dest/a/file.txt")
  130. removeDir("../dest")
  131. # createDir should not fail if `dir` is empty
  132. createDir("")
  133. when defined(linux): # bug #24174
  134. createDir("a/b")
  135. open("a/file.txt", fmWrite).close
  136. if not fileExists("a/fifoFile"):
  137. doAssert execCmd("mkfifo -m 600 a/fifoFile") == 0
  138. copyDir("a/", "../dest/a/", skipSpecial = true)
  139. copyDirWithPermissions("a/", "../dest2/a/", skipSpecial = true)
  140. removeDir("a")
  141. # Symlink handling in `copyFile`, `copyFileWithPermissions`, `copyFileToDir`,
  142. # `copyDir`, `copyDirWithPermissions`, `moveFile`, and `moveDir`.
  143. block:
  144. const symlinksAreHandled = not defined(windows)
  145. const dname = buildDir/"D20210116T140629"
  146. const subDir = dname/"sub"
  147. const subDir2 = dname/"sub2"
  148. const brokenSymlinkName = "D20210101T191320_BROKEN_SYMLINK"
  149. const brokenSymlink = dname/brokenSymlinkName
  150. const brokenSymlinkSrc = "D20210101T191320_nonexistent"
  151. const brokenSymlinkCopy = brokenSymlink & "_COPY"
  152. const brokenSymlinkInSubDir = subDir/brokenSymlinkName
  153. const brokenSymlinkInSubDir2 = subDir2/brokenSymlinkName
  154. createDir(subDir)
  155. createSymlink(brokenSymlinkSrc, brokenSymlink)
  156. # Test copyFile
  157. when symlinksAreHandled:
  158. doAssertRaises(OSError):
  159. copyFile(brokenSymlink, brokenSymlinkCopy)
  160. doAssertRaises(OSError):
  161. copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkFollow})
  162. copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkIgnore})
  163. doAssert not fileExists(brokenSymlinkCopy)
  164. copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkAsIs})
  165. when symlinksAreHandled:
  166. doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc
  167. removeFile(brokenSymlinkCopy)
  168. else:
  169. doAssert not fileExists(brokenSymlinkCopy)
  170. doAssertRaises(AssertionDefect):
  171. copyFile(brokenSymlink, brokenSymlinkCopy,
  172. {cfSymlinkAsIs, cfSymlinkFollow})
  173. # Test copyFileWithPermissions
  174. when symlinksAreHandled:
  175. doAssertRaises(OSError):
  176. copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy)
  177. doAssertRaises(OSError):
  178. copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
  179. options = {cfSymlinkFollow})
  180. copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
  181. options = {cfSymlinkIgnore})
  182. doAssert not fileExists(brokenSymlinkCopy)
  183. copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
  184. options = {cfSymlinkAsIs})
  185. when symlinksAreHandled:
  186. doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc
  187. removeFile(brokenSymlinkCopy)
  188. else:
  189. doAssert not fileExists(brokenSymlinkCopy)
  190. doAssertRaises(AssertionDefect):
  191. copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
  192. options = {cfSymlinkAsIs, cfSymlinkFollow})
  193. # Test copyFileToDir
  194. when symlinksAreHandled:
  195. doAssertRaises(OSError):
  196. copyFileToDir(brokenSymlink, subDir)
  197. doAssertRaises(OSError):
  198. copyFileToDir(brokenSymlink, subDir, {cfSymlinkFollow})
  199. copyFileToDir(brokenSymlink, subDir, {cfSymlinkIgnore})
  200. doAssert not fileExists(brokenSymlinkInSubDir)
  201. copyFileToDir(brokenSymlink, subDir, {cfSymlinkAsIs})
  202. when symlinksAreHandled:
  203. doAssert expandSymlink(brokenSymlinkInSubDir) == brokenSymlinkSrc
  204. removeFile(brokenSymlinkInSubDir)
  205. else:
  206. doAssert not fileExists(brokenSymlinkInSubDir)
  207. createSymlink(brokenSymlinkSrc, brokenSymlinkInSubDir)
  208. # Test copyDir
  209. copyDir(subDir, subDir2)
  210. when symlinksAreHandled:
  211. doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc
  212. else:
  213. doAssert not fileExists(brokenSymlinkInSubDir2)
  214. removeDir(subDir2)
  215. # Test copyDirWithPermissions
  216. copyDirWithPermissions(subDir, subDir2)
  217. when symlinksAreHandled:
  218. doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc
  219. else:
  220. doAssert not fileExists(brokenSymlinkInSubDir2)
  221. removeDir(subDir2)
  222. # Test moveFile
  223. moveFile(brokenSymlink, brokenSymlinkCopy)
  224. when not defined(windows):
  225. doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc
  226. else:
  227. doAssert symlinkExists(brokenSymlinkCopy)
  228. removeFile(brokenSymlinkCopy)
  229. # Test moveDir
  230. moveDir(subDir, subDir2)
  231. when not defined(windows):
  232. doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc
  233. else:
  234. doAssert symlinkExists(brokenSymlinkInSubDir2)
  235. removeDir(dname)
  236. block: # moveFile
  237. let tempDir = getTempDir() / "D20210609T151608"
  238. createDir(tempDir)
  239. defer: removeDir(tempDir)
  240. writeFile(tempDir / "a.txt", "")
  241. moveFile(tempDir / "a.txt", tempDir / "b.txt")
  242. doAssert not fileExists(tempDir / "a.txt")
  243. doAssert fileExists(tempDir / "b.txt")
  244. removeFile(tempDir / "b.txt")
  245. createDir(tempDir / "moveFile_test")
  246. writeFile(tempDir / "moveFile_test/a.txt", "")
  247. moveFile(tempDir / "moveFile_test/a.txt", tempDir / "moveFile_test/b.txt")
  248. doAssert not fileExists(tempDir / "moveFile_test/a.txt")
  249. doAssert fileExists(tempDir / "moveFile_test/b.txt")
  250. removeDir(tempDir / "moveFile_test")
  251. createDir(tempDir / "moveFile_test")
  252. writeFile(tempDir / "a.txt", "")
  253. moveFile(tempDir / "a.txt", tempDir / "moveFile_test/b.txt")
  254. doAssert not fileExists(tempDir / "a.txt")
  255. doAssert fileExists(tempDir / "moveFile_test/b.txt")
  256. removeDir(tempDir / "moveFile_test")
  257. block: # moveDir
  258. let tempDir = getTempDir() / "D20210609T161443"
  259. createDir(tempDir)
  260. defer: removeDir(tempDir)
  261. createDir(tempDir / "moveDir_test")
  262. moveDir(tempDir / "moveDir_test/", tempDir / "moveDir_test_dest")
  263. doAssert not dirExists(tempDir / "moveDir_test")
  264. doAssert dirExists(tempDir / "moveDir_test_dest")
  265. removeDir(tempDir / "moveDir_test_dest")
  266. createDir(tempDir / "moveDir_test")
  267. writeFile(tempDir / "moveDir_test/a.txt", "")
  268. moveDir(tempDir / "moveDir_test", tempDir / "moveDir_test_dest")
  269. doAssert not dirExists(tempDir / "moveDir_test")
  270. doAssert not fileExists(tempDir / "moveDir_test/a.txt")
  271. doAssert dirExists(tempDir / "moveDir_test_dest")
  272. doAssert fileExists(tempDir / "moveDir_test_dest/a.txt")
  273. removeDir(tempDir / "moveDir_test_dest")
  274. import times
  275. block modificationTime:
  276. # Test get/set modification times
  277. # Should support at least microsecond resolution
  278. let tm = fromUnix(0) + 100.microseconds
  279. writeFile("a", "")
  280. setLastModificationTime("a", tm)
  281. when defined(macosx):
  282. doAssert true
  283. else:
  284. doAssert getLastModificationTime("a") == tm
  285. removeFile("a")
  286. block walkDirRec:
  287. createDir("walkdir_test/a/b")
  288. open("walkdir_test/a/b/file_1", fmWrite).close()
  289. open("walkdir_test/a/file_2", fmWrite).close()
  290. for p in walkDirRec("walkdir_test"):
  291. doAssert p.fileExists
  292. doAssert p.startsWith("walkdir_test")
  293. var s: seq[string]
  294. for p in walkDirRec("walkdir_test", {pcFile}, {pcDir}, relative = true):
  295. s.add(p)
  296. doAssert s.len == 2
  297. doAssert "a" / "b" / "file_1" in s
  298. doAssert "a" / "file_2" in s
  299. removeDir("walkdir_test")
  300. import std/sequtils
  301. block: # walkDir
  302. doAssertRaises(OSError):
  303. for a in walkDir("nonexistent", checkDir = true): discard
  304. doAssertRaises(OSError):
  305. for p in walkDirRec("nonexistent", checkDir = true): discard
  306. when not defined(windows):
  307. block walkDirRelative:
  308. createDir("walkdir_test")
  309. createSymlink(".", "walkdir_test/c")
  310. for k, p in walkDir("walkdir_test", true):
  311. doAssert k == pcLinkToDir
  312. removeDir("walkdir_test")
  313. when defined(posix):
  314. block walkDirSpecial:
  315. createDir("walkdir_test")
  316. doAssert execShellCmd("mkfifo walkdir_test/fifo") == 0
  317. createSymlink("fifo", "walkdir_test/fifo_link")
  318. let withSpecialFiles = toSeq(walkDir("walkdir_test", relative = true))
  319. doAssert (withSpecialFiles.len == 2 and
  320. (pcFile, "fifo") in withSpecialFiles and
  321. (pcLinkToFile, "fifo_link") in withSpecialFiles)
  322. # now Unix special files are excluded from walkdir output:
  323. let skipSpecialFiles = toSeq(walkDir("walkdir_test", relative = true,
  324. skipSpecial = true))
  325. doAssert skipSpecialFiles.len == 0
  326. removeDir("walkdir_test")
  327. block normalizedPath:
  328. doAssert normalizedPath("") == ""
  329. block relative:
  330. doAssert normalizedPath(".") == "."
  331. doAssert normalizedPath("foo/..") == "."
  332. doAssert normalizedPath("foo//../bar/.") == "bar"
  333. doAssert normalizedPath("..") == ".."
  334. doAssert normalizedPath("../") == ".."
  335. doAssert normalizedPath("../..") == unixToNativePath"../.."
  336. doAssert normalizedPath("../a/..") == ".."
  337. doAssert normalizedPath("../a/../") == ".."
  338. doAssert normalizedPath("./") == "."
  339. block absolute:
  340. doAssert normalizedPath("/") == unixToNativePath"/"
  341. doAssert normalizedPath("/.") == unixToNativePath"/"
  342. doAssert normalizedPath("/..") == unixToNativePath"/.."
  343. doAssert normalizedPath("/../") == unixToNativePath"/.."
  344. doAssert normalizedPath("/../..") == unixToNativePath"/../.."
  345. doAssert normalizedPath("/../../") == unixToNativePath"/../.."
  346. doAssert normalizedPath("/../../../") == unixToNativePath"/../../.."
  347. doAssert normalizedPath("/a/b/../../foo") == unixToNativePath"/foo"
  348. doAssert normalizedPath("/a/b/../../../foo") == unixToNativePath"/../foo"
  349. doAssert normalizedPath("/./") == unixToNativePath"/"
  350. doAssert normalizedPath("//") == unixToNativePath"/"
  351. doAssert normalizedPath("///") == unixToNativePath"/"
  352. doAssert normalizedPath("/a//b") == unixToNativePath"/a/b"
  353. doAssert normalizedPath("/a///b") == unixToNativePath"/a/b"
  354. doAssert normalizedPath("/a/b/c/..") == unixToNativePath"/a/b"
  355. doAssert normalizedPath("/a/b/c/../") == unixToNativePath"/a/b"
  356. block isHidden:
  357. when defined(posix):
  358. doAssert ".foo.txt".isHidden
  359. doAssert "bar/.foo.ext".isHidden
  360. doAssert not "bar".isHidden
  361. doAssert not "foo/".isHidden
  362. doAssert ".foo/.".isHidden
  363. # Corner cases: `isHidden` is not yet `..` aware
  364. doAssert not ".foo/..".isHidden
  365. block absolutePath:
  366. doAssertRaises(ValueError): discard absolutePath("a", "b")
  367. doAssert absolutePath("a") == getCurrentDir() / "a"
  368. doAssert absolutePath("a", "/b") == "/b" / "a"
  369. when defined(posix):
  370. doAssert absolutePath("a", "/b/") == "/b" / "a"
  371. doAssert absolutePath("a", "/b/c") == "/b/c" / "a"
  372. doAssert absolutePath("/a", "b/") == "/a"
  373. block splitFile:
  374. doAssert splitFile("") == ("", "", "")
  375. doAssert splitFile("abc/") == ("abc", "", "")
  376. doAssert splitFile("/") == ("/", "", "")
  377. doAssert splitFile("./abc") == (".", "abc", "")
  378. doAssert splitFile(".txt") == ("", ".txt", "")
  379. doAssert splitFile("abc/.txt") == ("abc", ".txt", "")
  380. doAssert splitFile("abc") == ("", "abc", "")
  381. doAssert splitFile("abc.txt") == ("", "abc", ".txt")
  382. doAssert splitFile("/abc.txt") == ("/", "abc", ".txt")
  383. doAssert splitFile("/foo/abc.txt") == ("/foo", "abc", ".txt")
  384. doAssert splitFile("/foo/abc.txt.gz") == ("/foo", "abc.txt", ".gz")
  385. doAssert splitFile(".") == ("", ".", "")
  386. doAssert splitFile("abc/.") == ("abc", ".", "")
  387. doAssert splitFile("..") == ("", "..", "")
  388. doAssert splitFile("a/..") == ("a", "..", "")
  389. doAssert splitFile("/foo/abc....txt") == ("/foo", "abc...", ".txt")
  390. # execShellCmd is tested in tosproc
  391. block ospaths:
  392. doAssert unixToNativePath("") == ""
  393. doAssert unixToNativePath(".") == $CurDir
  394. doAssert unixToNativePath("..") == $ParDir
  395. doAssert isAbsolute(unixToNativePath("/"))
  396. doAssert isAbsolute(unixToNativePath("/", "a"))
  397. doAssert isAbsolute(unixToNativePath("/a"))
  398. doAssert isAbsolute(unixToNativePath("/a", "a"))
  399. doAssert isAbsolute(unixToNativePath("/a/b"))
  400. doAssert isAbsolute(unixToNativePath("/a/b", "a"))
  401. doAssert unixToNativePath("a/b") == joinPath("a", "b")
  402. when defined(macos):
  403. doAssert unixToNativePath("./") == ":"
  404. doAssert unixToNativePath("./abc") == ":abc"
  405. doAssert unixToNativePath("../abc") == "::abc"
  406. doAssert unixToNativePath("../../abc") == ":::abc"
  407. doAssert unixToNativePath("/abc", "a") == "abc"
  408. doAssert unixToNativePath("/abc/def", "a") == "abc:def"
  409. elif doslikeFileSystem:
  410. doAssert unixToNativePath("./") == ".\\"
  411. doAssert unixToNativePath("./abc") == ".\\abc"
  412. doAssert unixToNativePath("../abc") == "..\\abc"
  413. doAssert unixToNativePath("../../abc") == "..\\..\\abc"
  414. doAssert unixToNativePath("/abc", "a") == "a:\\abc"
  415. doAssert unixToNativePath("/abc/def", "a") == "a:\\abc\\def"
  416. else:
  417. #Tests for unix
  418. doAssert unixToNativePath("./") == "./"
  419. doAssert unixToNativePath("./abc") == "./abc"
  420. doAssert unixToNativePath("../abc") == "../abc"
  421. doAssert unixToNativePath("../../abc") == "../../abc"
  422. doAssert unixToNativePath("/abc", "a") == "/abc"
  423. doAssert unixToNativePath("/abc/def", "a") == "/abc/def"
  424. block extractFilenameTest:
  425. doAssert extractFilename("") == ""
  426. when defined(posix):
  427. doAssert extractFilename("foo/bar") == "bar"
  428. doAssert extractFilename("foo/bar.txt") == "bar.txt"
  429. doAssert extractFilename("foo/") == ""
  430. doAssert extractFilename("/") == ""
  431. when doslikeFileSystem:
  432. doAssert extractFilename(r"foo\bar") == "bar"
  433. doAssert extractFilename(r"foo\bar.txt") == "bar.txt"
  434. doAssert extractFilename(r"foo\") == ""
  435. doAssert extractFilename(r"C:\") == ""
  436. block lastPathPartTest:
  437. doAssert lastPathPart("") == ""
  438. when defined(posix):
  439. doAssert lastPathPart("foo/bar.txt") == "bar.txt"
  440. doAssert lastPathPart("foo/") == "foo"
  441. doAssert lastPathPart("/") == ""
  442. when doslikeFileSystem:
  443. doAssert lastPathPart(r"foo\bar.txt") == "bar.txt"
  444. doAssert lastPathPart(r"foo\") == "foo"
  445. template canon(x): untyped = normalizePath(x, '/')
  446. doAssert canon"/foo/../bar" == "/bar"
  447. doAssert canon"foo/../bar" == "bar"
  448. doAssert canon"/f/../bar///" == "/bar"
  449. doAssert canon"f/..////bar" == "bar"
  450. doAssert canon"../bar" == "../bar"
  451. doAssert canon"/../bar" == "/../bar"
  452. doAssert canon("foo/../../bar/") == "../bar"
  453. doAssert canon("./bla/blob/") == "bla/blob"
  454. doAssert canon(".hiddenFile") == ".hiddenFile"
  455. doAssert canon("./bla/../../blob/./zoo.nim") == "../blob/zoo.nim"
  456. doAssert canon("C:/file/to/this/long") == "C:/file/to/this/long"
  457. doAssert canon("") == ""
  458. doAssert canon("foobar") == "foobar"
  459. doAssert canon("f/////////") == "f"
  460. doAssert relativePath("/foo/bar//baz.nim", "/foo", '/') == "bar/baz.nim"
  461. doAssert normalizePath("./foo//bar/../baz", '/') == "foo/baz"
  462. doAssert relativePath("/Users/me/bar/z.nim", "/Users/other/bad", '/') == "../../me/bar/z.nim"
  463. doAssert relativePath("/Users/me/bar/z.nim", "/Users/other", '/') == "../me/bar/z.nim"
  464. # `//` is a UNC path, `/` is the current working directory's drive, so can't
  465. # run this test on Windows.
  466. when not doslikeFileSystem:
  467. doAssert relativePath("/Users///me/bar//z.nim", "//Users/", '/') == "me/bar/z.nim"
  468. doAssert relativePath("/Users/me/bar/z.nim", "/Users/me", '/') == "bar/z.nim"
  469. doAssert relativePath("", "/users/moo", '/') == ""
  470. doAssert relativePath("foo", "", '/') == "foo"
  471. doAssert relativePath("/foo", "/Foo", '/') == (when FileSystemCaseSensitive: "../foo" else: ".")
  472. doAssert relativePath("/Foo", "/foo", '/') == (when FileSystemCaseSensitive: "../Foo" else: ".")
  473. doAssert relativePath("/foo", "/fOO", '/') == (when FileSystemCaseSensitive: "../foo" else: ".")
  474. doAssert relativePath("/foO", "/foo", '/') == (when FileSystemCaseSensitive: "../foO" else: ".")
  475. doAssert relativePath("foo", ".", '/') == "foo"
  476. doAssert relativePath(".", ".", '/') == "."
  477. doAssert relativePath("..", ".", '/') == ".."
  478. doAssert relativePath("foo", "foo") == "."
  479. doAssert relativePath("", "foo") == ""
  480. doAssert relativePath("././/foo", "foo//./") == "."
  481. doAssert relativePath(getCurrentDir() / "bar", "foo") == "../bar".unixToNativePath
  482. doAssert relativePath("bar", getCurrentDir() / "foo") == "../bar".unixToNativePath
  483. when doslikeFileSystem:
  484. doAssert relativePath(r"c:\foo.nim", r"C:\") == r"foo.nim"
  485. doAssert relativePath(r"c:\foo\bar\baz.nim", r"c:\foo") == r"bar\baz.nim"
  486. doAssert relativePath(r"c:\foo\bar\baz.nim", r"d:\foo") == r"c:\foo\bar\baz.nim"
  487. doAssert relativePath(r"\foo\baz.nim", r"\foo") == r"baz.nim"
  488. doAssert relativePath(r"\foo\bar\baz.nim", r"\bar") == r"..\foo\bar\baz.nim"
  489. doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foo\bar") == r"baz.nim"
  490. doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foO\bar") == r"baz.nim"
  491. doAssert relativePath(r"\\foo\bar\baz.nim", r"\\bar\bar") == r"\\foo\bar\baz.nim"
  492. doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foo\car") == r"\\foo\bar\baz.nim"
  493. doAssert relativePath(r"\\foo\bar\baz.nim", r"\\goo\bar") == r"\\foo\bar\baz.nim"
  494. doAssert relativePath(r"\\foo\bar\baz.nim", r"c:\") == r"\\foo\bar\baz.nim"
  495. doAssert relativePath(r"\\foo\bar\baz.nim", r"\foo") == r"\\foo\bar\baz.nim"
  496. doAssert relativePath(r"c:\foo.nim", r"\foo") == r"c:\foo.nim"
  497. doAssert joinPath("usr", "") == unixToNativePath"usr"
  498. doAssert joinPath("", "lib") == "lib"
  499. doAssert joinPath("", "/lib") == unixToNativePath"/lib"
  500. doAssert joinPath("usr/", "/lib") == unixToNativePath"usr/lib"
  501. doAssert joinPath("", "") == unixToNativePath"" # issue #13455
  502. doAssert joinPath("", "/") == unixToNativePath"/"
  503. doAssert joinPath("/", "/") == unixToNativePath"/"
  504. doAssert joinPath("/", "") == unixToNativePath"/"
  505. doAssert joinPath("/" / "") == unixToNativePath"/" # weird test case...
  506. doAssert joinPath("/", "/a/b/c") == unixToNativePath"/a/b/c"
  507. doAssert joinPath("foo/", "") == unixToNativePath"foo/"
  508. doAssert joinPath("foo/", "abc") == unixToNativePath"foo/abc"
  509. doAssert joinPath("foo//./", "abc/.//") == unixToNativePath"foo/abc/"
  510. doAssert joinPath("foo", "abc") == unixToNativePath"foo/abc"
  511. doAssert joinPath("", "abc") == unixToNativePath"abc"
  512. doAssert joinPath("zook/.", "abc") == unixToNativePath"zook/abc"
  513. # controversial: inconsistent with `joinPath("zook/.","abc")`
  514. # on linux, `./foo` and `foo` are treated a bit differently for executables
  515. # but not `./foo/bar` and `foo/bar`
  516. doAssert joinPath(".", "/lib") == unixToNativePath"./lib"
  517. doAssert joinPath(".", "abc") == unixToNativePath"./abc"
  518. # cases related to issue #13455
  519. doAssert joinPath("foo", "", "") == "foo"
  520. doAssert joinPath("foo", "") == "foo"
  521. doAssert joinPath("foo/", "") == unixToNativePath"foo/"
  522. doAssert joinPath("foo/", ".") == "foo"
  523. doAssert joinPath("foo", "./") == unixToNativePath"foo/"
  524. doAssert joinPath("foo", "", "bar/") == unixToNativePath"foo/bar/"
  525. # issue #13579
  526. doAssert joinPath("/foo", "../a") == unixToNativePath"/a"
  527. doAssert joinPath("/foo/", "../a") == unixToNativePath"/a"
  528. doAssert joinPath("/foo/.", "../a") == unixToNativePath"/a"
  529. doAssert joinPath("/foo/.b", "../a") == unixToNativePath"/foo/a"
  530. doAssert joinPath("/foo///", "..//a/") == unixToNativePath"/a/"
  531. doAssert joinPath("foo/", "../a") == unixToNativePath"a"
  532. when doslikeFileSystem:
  533. doAssert joinPath("C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\", "..\\..\\VC\\vcvarsall.bat") == r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
  534. doAssert joinPath("C:\\foo", "..\\a") == r"C:\a"
  535. doAssert joinPath("C:\\foo\\", "..\\a") == r"C:\a"
  536. block getTempDir:
  537. block TMPDIR:
  538. # TMPDIR env var is not used if either of these are defined.
  539. when not (defined(tempDir) or defined(windows) or defined(android)):
  540. if existsEnv("TMPDIR"):
  541. let origTmpDir = getEnv("TMPDIR")
  542. putEnv("TMPDIR", "/mytmp")
  543. doAssert getTempDir() == "/mytmp/"
  544. delEnv("TMPDIR")
  545. doAssert getTempDir() == "/tmp/"
  546. putEnv("TMPDIR", origTmpDir)
  547. else:
  548. doAssert getTempDir() == "/tmp/"
  549. block: # getCacheDir
  550. doAssert getCacheDir().dirExists
  551. block isRelativeTo:
  552. doAssert isRelativeTo("/foo", "/")
  553. doAssert isRelativeTo("/foo/bar", "/foo")
  554. doAssert isRelativeTo("foo/bar", "foo")
  555. doAssert isRelativeTo("/foo/bar.nim", "/foo/bar.nim")
  556. doAssert isRelativeTo("./foo/", "foo")
  557. doAssert isRelativeTo("foo", "./foo/")
  558. doAssert isRelativeTo(".", ".")
  559. doAssert isRelativeTo("foo/bar", ".")
  560. doAssert not isRelativeTo("foo/bar.nims", "foo/bar.nim")
  561. doAssert not isRelativeTo("/foo2", "/foo")
  562. block: # quoteShellWindows
  563. doAssert quoteShellWindows("aaa") == "aaa"
  564. doAssert quoteShellWindows("aaa\"") == "aaa\\\""
  565. doAssert quoteShellWindows("") == "\"\""
  566. block: # quoteShellCommand
  567. when defined(windows):
  568. doAssert quoteShellCommand(["a b c", "d", "e"]) == """"a b c" d e"""
  569. doAssert quoteShellCommand(["""ab"c""", r"\", "d"]) == """ab\"c \ d"""
  570. doAssert quoteShellCommand(["""ab"c""", """ \""", "d"]) == """ab\"c " \\" d"""
  571. doAssert quoteShellCommand(["""a\\\b""", """de fg""", "h"]) == """a\\\b "de fg" h"""
  572. doAssert quoteShellCommand(["""a\"b""", "c", "d"]) == """a\\\"b c d"""
  573. doAssert quoteShellCommand(["""a\\b c""", "d", "e"]) == """"a\\b c" d e"""
  574. doAssert quoteShellCommand(["""a\\b\ c""", "d", "e"]) == """"a\\b\ c" d e"""
  575. doAssert quoteShellCommand(["ab", ""]) == """ab """""
  576. block: # quoteShellPosix
  577. doAssert quoteShellPosix("aaa") == "aaa"
  578. doAssert quoteShellPosix("aaa a") == "'aaa a'"
  579. doAssert quoteShellPosix("") == "''"
  580. doAssert quoteShellPosix("a'a") == "'a'\"'\"'a'"
  581. block: # quoteShell
  582. when defined(posix):
  583. doAssert quoteShell("") == "''"
  584. block: # normalizePathEnd
  585. # handle edge cases correctly: shouldn't affect whether path is
  586. # absolute/relative
  587. doAssert "".normalizePathEnd(true) == ""
  588. doAssert "".normalizePathEnd(false) == ""
  589. doAssert "/".normalizePathEnd(true) == $DirSep
  590. doAssert "/".normalizePathEnd(false) == $DirSep
  591. when defined(posix):
  592. doAssert "//".normalizePathEnd(false) == "/"
  593. doAssert "foo.bar//".normalizePathEnd == "foo.bar"
  594. doAssert "bar//".normalizePathEnd(trailingSep = true) == "bar/"
  595. when defined(windows):
  596. doAssert r"C:\foo\\".normalizePathEnd == r"C:\foo"
  597. doAssert r"C:\foo".normalizePathEnd(trailingSep = true) == r"C:\foo\"
  598. # this one is controversial: we could argue for returning `D:\` instead,
  599. # but this is simplest.
  600. doAssert r"D:\".normalizePathEnd == r"D:"
  601. doAssert r"E:/".normalizePathEnd(trailingSep = true) == r"E:\"
  602. doAssert "/".normalizePathEnd == r"\"
  603. import sugar
  604. block: # normalizeExe
  605. doAssert "".dup(normalizeExe) == ""
  606. when defined(posix):
  607. doAssert "foo".dup(normalizeExe) == "./foo"
  608. doAssert "foo/../bar".dup(normalizeExe) == "foo/../bar"
  609. when defined(windows):
  610. doAssert "foo".dup(normalizeExe) == "foo"
  611. block: # isAdmin
  612. let isAzure = existsEnv("TF_BUILD") # xxx factor with testament.specs.isAzure
  613. # In Azure on Windows tests run as an admin user
  614. if isAzure and defined(windows): doAssert isAdmin()
  615. # In Azure on POSIX tests run as a normal user
  616. if isAzure and defined(posix): doAssert not isAdmin()
  617. import sugar
  618. block: # normalizeExe
  619. doAssert "".dup(normalizeExe) == ""
  620. when defined(posix):
  621. doAssert "foo".dup(normalizeExe) == "./foo"
  622. doAssert "foo/../bar".dup(normalizeExe) == "foo/../bar"
  623. when defined(windows):
  624. doAssert "foo".dup(normalizeExe) == "foo"
  625. block: # isAdmin
  626. let isAzure = existsEnv("TF_BUILD") # xxx factor with testament.specs.isAzure
  627. # In Azure on Windows tests run as an admin user
  628. if isAzure and defined(windows): doAssert isAdmin()
  629. # In Azure on POSIX tests run as a normal user
  630. if isAzure and defined(posix): doAssert not isAdmin()
  631. when doslikeFileSystem:
  632. import std/private/ntpath
  633. block: # Bug #19103 UNC paths
  634. # Easiest way of generating a valid, readable and writable UNC path
  635. let tempDir = r"\\?\" & getTempDir()
  636. doAssert dirExists tempDir
  637. createDir tempDir / "test"
  638. removeDir tempDir / "test"
  639. createDir tempDir / "recursive" / "test"
  640. removeDir tempDir / "recursive" / "test"
  641. let tempDir2 = getTempDir()
  642. let (drive, pathNoDrive) = splitDrive(tempDir2)
  643. setCurrentDir drive
  644. doAssert cmpIgnoreCase(getCurrentDir().splitDrive.drive, drive) == 0
  645. # Test `\Users` path syntax on Windows by stripping away drive. `\`
  646. # resolves to the drive in current working directory. This drive will be
  647. # the same as `tempDir2` because of the `setCurrentDir` above.
  648. doAssert pathNoDrive[0] == '\\'
  649. createDir pathNoDrive / "test"
  650. doAssert dirExists pathNoDrive / "test"
  651. removeDir pathNoDrive / "test"
  652. doAssert splitPath("//?/c:") == ("//?/c:", "")
  653. doAssert relativePath("//?/c:///Users//me", "//?/c:", '/') == "Users/me"
  654. doAssert parentDir(r"\\?\c:") == r""
  655. doAssert parentDir(r"//?/c:/Users") == r"\\?\c:"
  656. doAssert parentDir(r"\\localhost\c$") == r""
  657. doAssert parentDir(r"\Users") == r"\"
  658. doAssert tailDir("//?/c:") == ""
  659. doAssert tailDir("//?/c:/Users") == "Users"
  660. doAssert tailDir(r"\\localhost\c$\Windows\System32") == r"Windows\System32"
  661. doAssert isRootDir("//?/c:")
  662. doAssert isRootDir("//?/UNC/localhost/c$")
  663. doAssert not isRootDir(r"\\?\c:\Users")
  664. doAssert parentDirs(r"C:\Users", fromRoot = true).toSeq == @[r"C:\", r"C:\Users"]
  665. doAssert parentDirs(r"C:\Users", fromRoot = false).toSeq == @[r"C:\Users", r"C:"]
  666. doAssert parentDirs(r"\\?\c:\Users", fromRoot = true).toSeq ==
  667. @[r"\\?\c:\", r"\\?\c:\Users"]
  668. doAssert parentDirs(r"\\?\c:\Users", fromRoot = false).toSeq ==
  669. @[r"\\?\c:\Users", r"\\?\c:"]
  670. doAssert parentDirs(r"//localhost/c$/Users", fromRoot = true).toSeq ==
  671. @[r"//localhost/c$/", r"//localhost/c$/Users"]
  672. doAssert parentDirs(r"//?/UNC/localhost/c$/Users", fromRoot = false).toSeq ==
  673. @[r"//?/UNC/localhost/c$/Users", r"\\?\UNC\localhost\c$"]
  674. doAssert parentDirs(r"\Users", fromRoot = true).toSeq == @[r"\", r"\Users"]
  675. doAssert parentDirs(r"\Users", fromRoot = false).toSeq == @[r"\Users", r"\"]
  676. doAssert r"//?/c:" /../ "d/e" == r"\\?\c:\d\e"
  677. doAssert r"//?/c:/Users" /../ "d/e" == r"\\?\c:\d\e"
  678. doAssert r"\\localhost\c$" /../ "d/e" == r"\\localhost\c$\d\e"
  679. doAssert splitFile("//?/c:") == ("//?/c:", "", "")
  680. doAssert splitFile("//?/c:/Users") == ("//?/c:", "Users", "")
  681. doAssert splitFile(r"\\localhost\c$\test.txt") == (r"\\localhost\c$", "test", ".txt")
  682. else:
  683. block: # parentDirs
  684. doAssert parentDirs("/home", fromRoot=true).toSeq == @["/", "/home"]
  685. doAssert parentDirs("/home", fromRoot=false).toSeq == @["/home", "/"]
  686. doAssert parentDirs("home", fromRoot=true).toSeq == @["home"]
  687. doAssert parentDirs("home", fromRoot=false).toSeq == @["home"]
  688. doAssert parentDirs("/home/user", fromRoot=true).toSeq == @["/", "/home/", "/home/user"]
  689. doAssert parentDirs("/home/user", fromRoot=false).toSeq == @["/home/user", "/home", "/"]
  690. doAssert parentDirs("home/user", fromRoot=true).toSeq == @["home/", "home/user"]
  691. doAssert parentDirs("home/user", fromRoot=false).toSeq == @["home/user", "home"]
  692. # https://github.com/nim-lang/Nim/pull/19643#issuecomment-1235102314
  693. block: # isValidFilename
  694. # Negative Tests.
  695. doAssert not isValidFilename("abcd", maxLen = 2)
  696. doAssert not isValidFilename("0123456789", maxLen = 8)
  697. doAssert not isValidFilename("con")
  698. doAssert not isValidFilename("aux")
  699. doAssert not isValidFilename("prn")
  700. doAssert not isValidFilename("OwO|UwU")
  701. doAssert not isValidFilename(" foo")
  702. doAssert not isValidFilename("foo ")
  703. doAssert not isValidFilename("foo.")
  704. doAssert not isValidFilename("con.txt")
  705. doAssert not isValidFilename("aux.bat")
  706. doAssert not isValidFilename("prn.exe")
  707. doAssert not isValidFilename("nim>.nim")
  708. doAssert not isValidFilename(" foo.log")
  709. # Positive Tests.
  710. doAssert isValidFilename("abcd", maxLen = 42.Positive)
  711. doAssert isValidFilename("c0n")
  712. doAssert isValidFilename("foo.aux")
  713. doAssert isValidFilename("bar.prn")
  714. doAssert isValidFilename("OwO_UwU")
  715. doAssert isValidFilename("cron")
  716. doAssert isValidFilename("ux.bat")
  717. doAssert isValidFilename("nim.nim")
  718. doAssert isValidFilename("foo.log")
  719. block: # searchExtPos
  720. doAssert "foo.nim".searchExtPos == 3
  721. doAssert "/foo.nim".searchExtPos == 4
  722. doAssert "".searchExtPos == -1
  723. doAssert "/".searchExtPos == -1
  724. doAssert "a.b/foo".searchExtPos == -1
  725. doAssert ".".searchExtPos == -1
  726. doAssert "foo.".searchExtPos == 3
  727. doAssert "foo..".searchExtPos == 4
  728. doAssert "..".searchExtPos == -1
  729. doAssert "...".searchExtPos == -1
  730. doAssert "./".searchExtPos == -1
  731. doAssert "../".searchExtPos == -1
  732. doAssert "/.".searchExtPos == -1
  733. doAssert "/..".searchExtPos == -1
  734. doAssert ".b".searchExtPos == -1
  735. doAssert "..b".searchExtPos == -1
  736. doAssert "/.b".searchExtPos == -1
  737. doAssert "a/.b".searchExtPos == -1
  738. doAssert ".a.b".searchExtPos == 2
  739. doAssert "a/.b.c".searchExtPos == 4
  740. doAssert "a/..b".searchExtPos == -1
  741. doAssert "a/b..c".searchExtPos == 4
  742. when doslikeFileSystem:
  743. doAssert "c:a.b".searchExtPos == 3
  744. doAssert "c:.a".searchExtPos == -1
  745. doAssert r"c:\.a".searchExtPos == -1
  746. doAssert "c:..a".searchExtPos == -1
  747. doAssert r"c:\..a".searchExtPos == -1
  748. doAssert "c:.a.b".searchExtPos == 4