Files
Nim/tests/stdlib/tos.nim
Roman Inflianskas e9b360c5df stdlib/os: handle symlinks in copy/move functions (#16709)
* stdlib/os: handle symlinks in copy/move functions

- Added optional `options` argument to `copyFile`, `copyFileToDir`, and
  `copyFileWithPermissions`. By default, symlinks are followed (copy files
  symlinks point to).
- `copyDir` and `copyDirWithPermissions` copy symlinks as symlinks (instead of
  skipping them as it was before).
- `moveFile` and `moveDir` move symlinks as symlinks (instead of skipping them
  sometimes as it was before).
- Added optional `followSymlinks` argument to `setFilePermissions`.

See also: https://github.com/nim-lang/RFCs/issues/319

Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>

* Address comments in #16709

Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>

* Address comments in #16709 (second iteration)

Skip symlinks on Windows.

Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>
2021-02-04 18:57:41 +01:00

654 lines
24 KiB
Nim

discard """
output: '''
All:
__really_obscure_dir_name/are.x
__really_obscure_dir_name/created
__really_obscure_dir_name/dirs
__really_obscure_dir_name/files.q
__really_obscure_dir_name/some
__really_obscure_dir_name/test
__really_obscure_dir_name/testing.r
__really_obscure_dir_name/these.txt
Files:
__really_obscure_dir_name/are.x
__really_obscure_dir_name/files.q
__really_obscure_dir_name/testing.r
__really_obscure_dir_name/these.txt
Dirs:
__really_obscure_dir_name/created
__really_obscure_dir_name/dirs
__really_obscure_dir_name/some
__really_obscure_dir_name/test
Raises
Raises
'''
"""
# test os path creation, iteration, and deletion
import os, strutils, pathnorm
from stdtest/specialpaths import buildDir
block fileOperations:
let files = @["these.txt", "are.x", "testing.r", "files.q"]
let dirs = @["some", "created", "test", "dirs"]
let dname = "__really_obscure_dir_name"
createDir(dname)
doAssert dirExists(dname)
block: # copyFile, copyFileToDir
doAssertRaises(OSError): copyFile(dname/"nonexistant.txt", dname/"nonexistant.txt")
let fname = "D20201009T112235"
let fname2 = "D20201009T112235.2"
let str = "foo1\0foo2\nfoo3\0"
let file = dname/fname
let file2 = dname/fname2
writeFile(file, str)
doAssert readFile(file) == str
let sub = "sub"
doAssertRaises(OSError): copyFile(file, dname/sub/fname2)
doAssertRaises(OSError): copyFileToDir(file, dname/sub)
doAssertRaises(ValueError): copyFileToDir(file, "")
copyFile(file, file2)
doAssert fileExists(file2)
doAssert readFile(file2) == str
createDir(dname/sub)
copyFileToDir(file, dname/sub)
doAssert fileExists(dname/sub/fname)
removeDir(dname/sub)
doAssert not dirExists(dname/sub)
removeFile(file)
removeFile(file2)
# Test creating files and dirs
for dir in dirs:
createDir(dname/dir)
doAssert dirExists(dname/dir)
for file in files:
let fh = open(dname/file, fmReadWrite)
fh.close()
doAssert fileExists(dname/file)
echo "All:"
template norm(x): untyped =
(when defined(windows): x.replace('\\', '/') else: x)
for path in walkPattern(dname/"*"):
echo path.norm
echo "Files:"
for path in walkFiles(dname/"*"):
echo path.norm
echo "Dirs:"
for path in walkDirs(dname/"*"):
echo path.norm
# Test removal of files dirs
for dir in dirs:
removeDir(dname/dir)
doAssert: not dirExists(dname/dir)
for file in files:
removeFile(dname/file)
doAssert: not fileExists(dname/file)
removeDir(dname)
doAssert: not dirExists(dname)
# createDir should create recursive directories
createDir(dirs[0] / dirs[1])
doAssert dirExists(dirs[0] / dirs[1]) # true
removeDir(dirs[0])
# createDir should properly handle trailing separator
createDir(dname / "")
doAssert dirExists(dname) # true
removeDir(dname)
# createDir should raise IOError if the path exists
# and is not a directory
open(dname, fmWrite).close
try:
createDir(dname)
except IOError:
echo "Raises"
removeFile(dname)
# removeFile should not remove directory
createDir(dname)
try:
removeFile(dname)
except OSError:
echo "Raises"
removeDir(dname)
# test copyDir:
createDir("a/b")
open("a/b/file.txt", fmWrite).close
createDir("a/b/c")
open("a/b/c/fileC.txt", fmWrite).close
copyDir("a", "../dest/a")
removeDir("a")
doAssert dirExists("../dest/a/b")
doAssert fileExists("../dest/a/b/file.txt")
doAssert fileExists("../dest/a/b/c/fileC.txt")
removeDir("../dest")
# test copyDir:
# if separator at the end of a path
createDir("a/b")
open("a/file.txt", fmWrite).close
copyDir("a/", "../dest/a/")
removeDir("a")
doAssert dirExists("../dest/a/b")
doAssert fileExists("../dest/a/file.txt")
removeDir("../dest")
# Symlink handling in `copyFile`, `copyFileWithPermissions`, `copyFileToDir`,
# `copyDir`, `copyDirWithPermissions`, `moveFile`, and `moveDir`.
block:
const symlinksAreHandled = not defined(windows)
const dname = buildDir/"D20210116T140629"
const subDir = dname/"sub"
const subDir2 = dname/"sub2"
const brokenSymlinkName = "D20210101T191320_BROKEN_SYMLINK"
const brokenSymlink = dname/brokenSymlinkName
const brokenSymlinkSrc = "D20210101T191320_nonexistant"
const brokenSymlinkCopy = brokenSymlink & "_COPY"
const brokenSymlinkInSubDir = subDir/brokenSymlinkName
const brokenSymlinkInSubDir2 = subDir2/brokenSymlinkName
createDir(subDir)
createSymlink(brokenSymlinkSrc, brokenSymlink)
# Test copyFile
when symlinksAreHandled:
doAssertRaises(OSError):
copyFile(brokenSymlink, brokenSymlinkCopy)
doAssertRaises(OSError):
copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkFollow})
copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkIgnore})
doAssert not fileExists(brokenSymlinkCopy)
copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkAsIs})
when symlinksAreHandled:
doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc
removeFile(brokenSymlinkCopy)
else:
doAssert not fileExists(brokenSymlinkCopy)
doAssertRaises(AssertionDefect):
copyFile(brokenSymlink, brokenSymlinkCopy,
{cfSymlinkAsIs, cfSymlinkFollow})
# Test copyFileWithPermissions
when symlinksAreHandled:
doAssertRaises(OSError):
copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy)
doAssertRaises(OSError):
copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
options = {cfSymlinkFollow})
copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
options = {cfSymlinkIgnore})
doAssert not fileExists(brokenSymlinkCopy)
copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
options = {cfSymlinkAsIs})
when symlinksAreHandled:
doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc
removeFile(brokenSymlinkCopy)
else:
doAssert not fileExists(brokenSymlinkCopy)
doAssertRaises(AssertionDefect):
copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
options = {cfSymlinkAsIs, cfSymlinkFollow})
# Test copyFileToDir
when symlinksAreHandled:
doAssertRaises(OSError):
copyFileToDir(brokenSymlink, subDir)
doAssertRaises(OSError):
copyFileToDir(brokenSymlink, subDir, {cfSymlinkFollow})
copyFileToDir(brokenSymlink, subDir, {cfSymlinkIgnore})
doAssert not fileExists(brokenSymlinkInSubDir)
copyFileToDir(brokenSymlink, subDir, {cfSymlinkAsIs})
when symlinksAreHandled:
doAssert expandSymlink(brokenSymlinkInSubDir) == brokenSymlinkSrc
removeFile(brokenSymlinkInSubDir)
else:
doAssert not fileExists(brokenSymlinkInSubDir)
createSymlink(brokenSymlinkSrc, brokenSymlinkInSubDir)
# Test copyDir
copyDir(subDir, subDir2)
when symlinksAreHandled:
doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc
else:
doAssert not fileExists(brokenSymlinkInSubDir2)
removeDir(subDir2)
# Test copyDirWithPermissions
copyDirWithPermissions(subDir, subDir2)
when symlinksAreHandled:
doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc
else:
doAssert not fileExists(brokenSymlinkInSubDir2)
removeDir(subDir2)
# Test moveFile
moveFile(brokenSymlink, brokenSymlinkCopy)
when not defined(windows):
doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc
else:
doAssert symlinkExists(brokenSymlinkCopy)
removeFile(brokenSymlinkCopy)
# Test moveDir
moveDir(subDir, subDir2)
when not defined(windows):
doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc
else:
doAssert symlinkExists(brokenSymlinkInSubDir2)
removeDir(dname)
import times
block modificationTime:
# Test get/set modification times
# Should support at least microsecond resolution
let tm = fromUnix(0) + 100.microseconds
writeFile("a", "")
setLastModificationTime("a", tm)
when defined(macosx):
doAssert true
else:
doAssert getLastModificationTime("a") == tm
removeFile("a")
block walkDirRec:
createDir("walkdir_test/a/b")
open("walkdir_test/a/b/file_1", fmWrite).close()
open("walkdir_test/a/file_2", fmWrite).close()
for p in walkDirRec("walkdir_test"):
doAssert p.fileExists
doAssert p.startsWith("walkdir_test")
var s: seq[string]
for p in walkDirRec("walkdir_test", {pcFile}, {pcDir}, relative=true):
s.add(p)
doAssert s.len == 2
doAssert "a" / "b" / "file_1" in s
doAssert "a" / "file_2" in s
removeDir("walkdir_test")
block: # walkDir
doAssertRaises(OSError):
for a in walkDir("nonexistant", checkDir = true): discard
doAssertRaises(OSError):
for p in walkDirRec("nonexistant", checkDir = true): discard
when not defined(windows):
block walkDirRelative:
createDir("walkdir_test")
createSymlink(".", "walkdir_test/c")
for k, p in walkDir("walkdir_test", true):
doAssert k == pcLinkToDir
removeDir("walkdir_test")
block normalizedPath:
doAssert normalizedPath("") == ""
block relative:
doAssert normalizedPath(".") == "."
doAssert normalizedPath("foo/..") == "."
doAssert normalizedPath("foo//../bar/.") == "bar"
doAssert normalizedPath("..") == ".."
doAssert normalizedPath("../") == ".."
doAssert normalizedPath("../..") == unixToNativePath"../.."
doAssert normalizedPath("../a/..") == ".."
doAssert normalizedPath("../a/../") == ".."
doAssert normalizedPath("./") == "."
block absolute:
doAssert normalizedPath("/") == unixToNativePath"/"
doAssert normalizedPath("/.") == unixToNativePath"/"
doAssert normalizedPath("/..") == unixToNativePath"/.."
doAssert normalizedPath("/../") == unixToNativePath"/.."
doAssert normalizedPath("/../..") == unixToNativePath"/../.."
doAssert normalizedPath("/../../") == unixToNativePath"/../.."
doAssert normalizedPath("/../../../") == unixToNativePath"/../../.."
doAssert normalizedPath("/a/b/../../foo") == unixToNativePath"/foo"
doAssert normalizedPath("/a/b/../../../foo") == unixToNativePath"/../foo"
doAssert normalizedPath("/./") == unixToNativePath"/"
doAssert normalizedPath("//") == unixToNativePath"/"
doAssert normalizedPath("///") == unixToNativePath"/"
doAssert normalizedPath("/a//b") == unixToNativePath"/a/b"
doAssert normalizedPath("/a///b") == unixToNativePath"/a/b"
doAssert normalizedPath("/a/b/c/..") == unixToNativePath"/a/b"
doAssert normalizedPath("/a/b/c/../") == unixToNativePath"/a/b"
block isHidden:
when defined(posix):
doAssert ".foo.txt".isHidden
doAssert "bar/.foo.ext".isHidden
doAssert not "bar".isHidden
doAssert not "foo/".isHidden
doAssert ".foo/.".isHidden
# Corner cases: `isHidden` is not yet `..` aware
doAssert not ".foo/..".isHidden
block absolutePath:
doAssertRaises(ValueError): discard absolutePath("a", "b")
doAssert absolutePath("a") == getCurrentDir() / "a"
doAssert absolutePath("a", "/b") == "/b" / "a"
when defined(Posix):
doAssert absolutePath("a", "/b/") == "/b" / "a"
doAssert absolutePath("a", "/b/c") == "/b/c" / "a"
doAssert absolutePath("/a", "b/") == "/a"
block splitFile:
doAssert splitFile("") == ("", "", "")
doAssert splitFile("abc/") == ("abc", "", "")
doAssert splitFile("/") == ("/", "", "")
doAssert splitFile("./abc") == (".", "abc", "")
doAssert splitFile(".txt") == ("", ".txt", "")
doAssert splitFile("abc/.txt") == ("abc", ".txt", "")
doAssert splitFile("abc") == ("", "abc", "")
doAssert splitFile("abc.txt") == ("", "abc", ".txt")
doAssert splitFile("/abc.txt") == ("/", "abc", ".txt")
doAssert splitFile("/foo/abc.txt") == ("/foo", "abc", ".txt")
doAssert splitFile("/foo/abc.txt.gz") == ("/foo", "abc.txt", ".gz")
doAssert splitFile(".") == ("", ".", "")
doAssert splitFile("abc/.") == ("abc", ".", "")
doAssert splitFile("..") == ("", "..", "")
doAssert splitFile("a/..") == ("a", "..", "")
doAssert splitFile("/foo/abc....txt") == ("/foo", "abc...", ".txt")
# execShellCmd is tested in tosproc
block ospaths:
doAssert unixToNativePath("") == ""
doAssert unixToNativePath(".") == $CurDir
doAssert unixToNativePath("..") == $ParDir
doAssert isAbsolute(unixToNativePath("/"))
doAssert isAbsolute(unixToNativePath("/", "a"))
doAssert isAbsolute(unixToNativePath("/a"))
doAssert isAbsolute(unixToNativePath("/a", "a"))
doAssert isAbsolute(unixToNativePath("/a/b"))
doAssert isAbsolute(unixToNativePath("/a/b", "a"))
doAssert unixToNativePath("a/b") == joinPath("a", "b")
when defined(macos):
doAssert unixToNativePath("./") == ":"
doAssert unixToNativePath("./abc") == ":abc"
doAssert unixToNativePath("../abc") == "::abc"
doAssert unixToNativePath("../../abc") == ":::abc"
doAssert unixToNativePath("/abc", "a") == "abc"
doAssert unixToNativePath("/abc/def", "a") == "abc:def"
elif doslikeFileSystem:
doAssert unixToNativePath("./") == ".\\"
doAssert unixToNativePath("./abc") == ".\\abc"
doAssert unixToNativePath("../abc") == "..\\abc"
doAssert unixToNativePath("../../abc") == "..\\..\\abc"
doAssert unixToNativePath("/abc", "a") == "a:\\abc"
doAssert unixToNativePath("/abc/def", "a") == "a:\\abc\\def"
else:
#Tests for unix
doAssert unixToNativePath("./") == "./"
doAssert unixToNativePath("./abc") == "./abc"
doAssert unixToNativePath("../abc") == "../abc"
doAssert unixToNativePath("../../abc") == "../../abc"
doAssert unixToNativePath("/abc", "a") == "/abc"
doAssert unixToNativePath("/abc/def", "a") == "/abc/def"
block extractFilenameTest:
doAssert extractFilename("") == ""
when defined(posix):
doAssert extractFilename("foo/bar") == "bar"
doAssert extractFilename("foo/bar.txt") == "bar.txt"
doAssert extractFilename("foo/") == ""
doAssert extractFilename("/") == ""
when doslikeFileSystem:
doAssert extractFilename(r"foo\bar") == "bar"
doAssert extractFilename(r"foo\bar.txt") == "bar.txt"
doAssert extractFilename(r"foo\") == ""
doAssert extractFilename(r"C:\") == ""
block lastPathPartTest:
doAssert lastPathPart("") == ""
when defined(posix):
doAssert lastPathPart("foo/bar.txt") == "bar.txt"
doAssert lastPathPart("foo/") == "foo"
doAssert lastPathPart("/") == ""
when doslikeFileSystem:
doAssert lastPathPart(r"foo\bar.txt") == "bar.txt"
doAssert lastPathPart(r"foo\") == "foo"
template canon(x): untyped = normalizePath(x, '/')
doAssert canon"/foo/../bar" == "/bar"
doAssert canon"foo/../bar" == "bar"
doAssert canon"/f/../bar///" == "/bar"
doAssert canon"f/..////bar" == "bar"
doAssert canon"../bar" == "../bar"
doAssert canon"/../bar" == "/../bar"
doAssert canon("foo/../../bar/") == "../bar"
doAssert canon("./bla/blob/") == "bla/blob"
doAssert canon(".hiddenFile") == ".hiddenFile"
doAssert canon("./bla/../../blob/./zoo.nim") == "../blob/zoo.nim"
doAssert canon("C:/file/to/this/long") == "C:/file/to/this/long"
doAssert canon("") == ""
doAssert canon("foobar") == "foobar"
doAssert canon("f/////////") == "f"
doAssert relativePath("/foo/bar//baz.nim", "/foo", '/') == "bar/baz.nim"
doAssert normalizePath("./foo//bar/../baz", '/') == "foo/baz"
doAssert relativePath("/Users/me/bar/z.nim", "/Users/other/bad", '/') == "../../me/bar/z.nim"
doAssert relativePath("/Users/me/bar/z.nim", "/Users/other", '/') == "../me/bar/z.nim"
doAssert relativePath("/Users///me/bar//z.nim", "//Users/", '/') == "me/bar/z.nim"
doAssert relativePath("/Users/me/bar/z.nim", "/Users/me", '/') == "bar/z.nim"
doAssert relativePath("", "/users/moo", '/') == ""
doAssert relativePath("foo", "", '/') == "foo"
doAssert relativePath("/foo", "/Foo", '/') == (when FileSystemCaseSensitive: "../foo" else: ".")
doAssert relativePath("/Foo", "/foo", '/') == (when FileSystemCaseSensitive: "../Foo" else: ".")
doAssert relativePath("/foo", "/fOO", '/') == (when FileSystemCaseSensitive: "../foo" else: ".")
doAssert relativePath("/foO", "/foo", '/') == (when FileSystemCaseSensitive: "../foO" else: ".")
doAssert relativePath("foo", ".", '/') == "foo"
doAssert relativePath(".", ".", '/') == "."
doAssert relativePath("..", ".", '/') == ".."
doAssert relativePath("foo", "foo") == "."
doAssert relativePath("", "foo") == ""
doAssert relativePath("././/foo", "foo//./") == "."
doAssert relativePath(getCurrentDir() / "bar", "foo") == "../bar".unixToNativePath
doAssert relativePath("bar", getCurrentDir() / "foo") == "../bar".unixToNativePath
when doslikeFileSystem:
doAssert relativePath(r"c:\foo.nim", r"C:\") == r"foo.nim"
doAssert relativePath(r"c:\foo\bar\baz.nim", r"c:\foo") == r"bar\baz.nim"
doAssert relativePath(r"c:\foo\bar\baz.nim", r"d:\foo") == r"c:\foo\bar\baz.nim"
doAssert relativePath(r"\foo\baz.nim", r"\foo") == r"baz.nim"
doAssert relativePath(r"\foo\bar\baz.nim", r"\bar") == r"..\foo\bar\baz.nim"
doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foo\bar") == r"baz.nim"
doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foO\bar") == r"baz.nim"
doAssert relativePath(r"\\foo\bar\baz.nim", r"\\bar\bar") == r"\\foo\bar\baz.nim"
doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foo\car") == r"\\foo\bar\baz.nim"
doAssert relativePath(r"\\foo\bar\baz.nim", r"\\goo\bar") == r"\\foo\bar\baz.nim"
doAssert relativePath(r"\\foo\bar\baz.nim", r"c:\") == r"\\foo\bar\baz.nim"
doAssert relativePath(r"\\foo\bar\baz.nim", r"\foo") == r"\\foo\bar\baz.nim"
doAssert relativePath(r"c:\foo.nim", r"\foo") == r"c:\foo.nim"
doAssert joinPath("usr", "") == unixToNativePath"usr"
doAssert joinPath("", "lib") == "lib"
doAssert joinPath("", "/lib") == unixToNativePath"/lib"
doAssert joinPath("usr/", "/lib") == unixToNativePath"usr/lib"
doAssert joinPath("", "") == unixToNativePath"" # issue #13455
doAssert joinPath("", "/") == unixToNativePath"/"
doAssert joinPath("/", "/") == unixToNativePath"/"
doAssert joinPath("/", "") == unixToNativePath"/"
doAssert joinPath("/" / "") == unixToNativePath"/" # weird test case...
doAssert joinPath("/", "/a/b/c") == unixToNativePath"/a/b/c"
doAssert joinPath("foo/","") == unixToNativePath"foo/"
doAssert joinPath("foo/","abc") == unixToNativePath"foo/abc"
doAssert joinPath("foo//./","abc/.//") == unixToNativePath"foo/abc/"
doAssert joinPath("foo","abc") == unixToNativePath"foo/abc"
doAssert joinPath("","abc") == unixToNativePath"abc"
doAssert joinPath("gook/.","abc") == unixToNativePath"gook/abc"
# controversial: inconsistent with `joinPath("gook/.","abc")`
# on linux, `./foo` and `foo` are treated a bit differently for executables
# but not `./foo/bar` and `foo/bar`
doAssert joinPath(".", "/lib") == unixToNativePath"./lib"
doAssert joinPath(".","abc") == unixToNativePath"./abc"
# cases related to issue #13455
doAssert joinPath("foo", "", "") == "foo"
doAssert joinPath("foo", "") == "foo"
doAssert joinPath("foo/", "") == unixToNativePath"foo/"
doAssert joinPath("foo/", ".") == "foo"
doAssert joinPath("foo", "./") == unixToNativePath"foo/"
doAssert joinPath("foo", "", "bar/") == unixToNativePath"foo/bar/"
# issue #13579
doAssert joinPath("/foo", "../a") == unixToNativePath"/a"
doAssert joinPath("/foo/", "../a") == unixToNativePath"/a"
doAssert joinPath("/foo/.", "../a") == unixToNativePath"/a"
doAssert joinPath("/foo/.b", "../a") == unixToNativePath"/foo/a"
doAssert joinPath("/foo///", "..//a/") == unixToNativePath"/a/"
doAssert joinPath("foo/", "../a") == unixToNativePath"a"
when doslikeFileSystem:
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"
doAssert joinPath("C:\\foo", "..\\a") == r"C:\a"
doAssert joinPath("C:\\foo\\", "..\\a") == r"C:\a"
block getTempDir:
block TMPDIR:
# TMPDIR env var is not used if either of these are defined.
when not (defined(tempDir) or defined(windows) or defined(android)):
if existsEnv("TMPDIR"):
let origTmpDir = getEnv("TMPDIR")
putEnv("TMPDIR", "/mytmp")
doAssert getTempDir() == "/mytmp/"
delEnv("TMPDIR")
doAssert getTempDir() == "/tmp/"
putEnv("TMPDIR", origTmpDir)
else:
doAssert getTempDir() == "/tmp/"
block osenv:
block delEnv:
const dummyEnvVar = "DUMMY_ENV_VAR" # This env var wouldn't be likely to exist to begin with
doAssert existsEnv(dummyEnvVar) == false
putEnv(dummyEnvVar, "1")
doAssert existsEnv(dummyEnvVar) == true
delEnv(dummyEnvVar)
doAssert existsEnv(dummyEnvVar) == false
delEnv(dummyEnvVar) # deleting an already deleted env var
doAssert existsEnv(dummyEnvVar) == false
block isRelativeTo:
doAssert isRelativeTo("/foo", "/")
doAssert isRelativeTo("/foo/bar", "/foo")
doAssert isRelativeTo("foo/bar", "foo")
doAssert isRelativeTo("/foo/bar.nim", "/foo/bar.nim")
doAssert isRelativeTo("./foo/", "foo")
doAssert isRelativeTo("foo", "./foo/")
doAssert isRelativeTo(".", ".")
doAssert isRelativeTo("foo/bar", ".")
doAssert not isRelativeTo("foo/bar.nims", "foo/bar.nim")
doAssert not isRelativeTo("/foo2", "/foo")
block: # quoteShellWindows
doAssert quoteShellWindows("aaa") == "aaa"
doAssert quoteShellWindows("aaa\"") == "aaa\\\""
doAssert quoteShellWindows("") == "\"\""
block: # quoteShellWindows
doAssert quoteShellPosix("aaa") == "aaa"
doAssert quoteShellPosix("aaa a") == "'aaa a'"
doAssert quoteShellPosix("") == "''"
doAssert quoteShellPosix("a'a") == "'a'\"'\"'a'"
block: # quoteShell
when defined(posix):
doAssert quoteShell("") == "''"
block: # normalizePathEnd
# handle edge cases correctly: shouldn't affect whether path is
# absolute/relative
doAssert "".normalizePathEnd(true) == ""
doAssert "".normalizePathEnd(false) == ""
doAssert "/".normalizePathEnd(true) == $DirSep
doAssert "/".normalizePathEnd(false) == $DirSep
when defined(posix):
doAssert "//".normalizePathEnd(false) == "/"
doAssert "foo.bar//".normalizePathEnd == "foo.bar"
doAssert "bar//".normalizePathEnd(trailingSep = true) == "bar/"
when defined(Windows):
doAssert r"C:\foo\\".normalizePathEnd == r"C:\foo"
doAssert r"C:\foo".normalizePathEnd(trailingSep = true) == r"C:\foo\"
# this one is controversial: we could argue for returning `D:\` instead,
# but this is simplest.
doAssert r"D:\".normalizePathEnd == r"D:"
doAssert r"E:/".normalizePathEnd(trailingSep = true) == r"E:\"
doAssert "/".normalizePathEnd == r"\"
block: # isValidFilename
# Negative Tests.
doAssert not isValidFilename("abcd", maxLen = 2)
doAssert not isValidFilename("0123456789", maxLen = 8)
doAssert not isValidFilename("con")
doAssert not isValidFilename("aux")
doAssert not isValidFilename("prn")
doAssert not isValidFilename("OwO|UwU")
doAssert not isValidFilename(" foo")
doAssert not isValidFilename("foo ")
doAssert not isValidFilename("foo.")
doAssert not isValidFilename("con.txt")
doAssert not isValidFilename("aux.bat")
doAssert not isValidFilename("prn.exe")
doAssert not isValidFilename("nim>.nim")
doAssert not isValidFilename(" foo.log")
# Positive Tests.
doAssert isValidFilename("abcd", maxLen = 42.Positive)
doAssert isValidFilename("c0n")
doAssert isValidFilename("foo.aux")
doAssert isValidFilename("bar.prn")
doAssert isValidFilename("OwO_UwU")
doAssert isValidFilename("cron")
doAssert isValidFilename("ux.bat")
doAssert isValidFilename("nim.nim")
doAssert isValidFilename("foo.log")
import sugar
block: # normalizeExe
doAssert "".dup(normalizeExe) == ""
when defined(posix):
doAssert "foo".dup(normalizeExe) == "./foo"
doAssert "foo/../bar".dup(normalizeExe) == "foo/../bar"
when defined(windows):
doAssert "foo".dup(normalizeExe) == "foo"