Files
julia/test/path.jl
Stefan Karpinski cc3a071090 backticks: implement tilde expansion (#61397)
- path: add homedir(username) method for looking up other users' home dirs
- path: overhaul expanduser and contractuser for cross-platform support
- REPL: unify shell mode and backtick command completion escaping
- shell: expand tildes in backtick commands with REPL completion support
2026-04-10 20:12:24 -04:00

496 lines
26 KiB
Julia
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# This file is a part of Julia. License is MIT: https://julialang.org/license
using Random: randstring
isdefined(Main, :samepath) || @eval Main include("testhelpers/samepath.jl")
using Main: samepath
@testset "basic path functions for $S" for S in (String, SubString, GenericString)
dir = pwd()
sep = Base.Filesystem.path_separator
@testset "isabspath and abspath" begin
@test abspath(S("foo")) == "$dir$(sep)foo"
@test abspath(S("foo"), S("bar")) == "$dir$(sep)foo$(sep)bar"
@test isabspath(S(homedir()))
@test !isabspath(S("foo"))
end
if Sys.iswindows()
@testset "issue #38491" begin
pwd_drive = uppercase(splitdrive(pwd())[1])
drive = (pwd_drive == "X:") ? "Y:" : "X:"
@test abspath("$(lowercase(drive))a\\b\\c") == "$(lowercase(drive))\\a\\b\\c"
@test abspath("$(uppercase(drive))a\\b\\c") == "$(uppercase(drive))\\a\\b\\c"
@test abspath("$(lowercase(drive))a") == "$(lowercase(drive))\\a"
@test abspath("$(uppercase(drive))a") == "$(uppercase(drive))\\a"
@test abspath(lowercase(drive)) == "$(lowercase(drive))\\"
@test abspath(uppercase(drive)) == "$(uppercase(drive))\\"
@test lowercase(abspath("$(pwd_drive)a\\b\\c")) == lowercase(joinpath(pwd(), "a\\b\\c"))
@test lowercase(abspath("$(pwd_drive)a")) == lowercase(joinpath(pwd(), "a"))
@test lowercase(abspath(lowercase(pwd_drive))) == lowercase("$(pwd())\\")
@test lowercase(abspath(uppercase(pwd_drive))) == lowercase("$(pwd())\\")
end
end
@test basename(S("foo$(sep)bar")) == "bar"
@test dirname(S("foo$(sep)bar")) == "foo"
@testset "expanduser" begin
@test expanduser(S("")) == ""
@test expanduser(S("x")) == "x"
@test expanduser(S("~")) == homedir()
@test expanduser(S("~$(Base.Filesystem.path_separator)foo")) == joinpath(homedir(), "foo")
if Sys.iswindows()
# expanduser preserves the separator from the input path
home = homedir()
@test expanduser(S("~/foo")) == replace(home, '\\' => '/') * "/foo"
@test expanduser(S("~\\foo")) == replace(home, '/' => '\\') * "\\foo"
end
if !Sys.iswindows()
# ~username expansion (Unix only)
me = Sys.username()
@test samepath(expanduser(S("~$me")), homedir(me))
@test samepath(expanduser(S("~$me/bar")), joinpath(homedir(me), "bar"))
# unknown user is left unexpanded
nouser = "nouser_" * randstring(12)
@test expanduser(S("~$nouser")) == "~$nouser"
end
end
@testset "contractuser" begin
# contractuser is left-inverse of expanduser
@test contractuser(S(homedir())) == "~"
@test contractuser(S(joinpath(homedir(), "x"))) == "~$(sep)x"
if !Sys.iswindows()
@test contractuser(S("/foo/bar")) == "/foo/bar"
me = Sys.username()
# current user's home contracts to ~ or ~username via stat
result = contractuser(S(homedir()))
@test result == "~" || result == "~$me"
end
# round-trip: expanduser(contractuser(p)) == p for home-relative paths
p = joinpath(homedir(), "some", "path")
@test expanduser(contractuser(S(p))) == p
end
@testset "isdirpath" begin
@test !isdirpath(S("foo"))
@test isdirpath(S("foo$sep"))
@test isdirpath(S(""))
@test isdirpath(S("."))
@test isdirpath(S(".."))
# After https://github.com/JuliaLang/julia/pull/60677, paths
# with "\n", ".\n" or "..\n" after the last separator are
# not accepted as directories.
@test !isdirpath("\n")
@test !isdirpath(".\n")
@test !isdirpath("..\n")
@test !isdirpath("a/\n")
@test !isdirpath("a/.\n")
@test !isdirpath("a/..\n")
end
@testset "joinpath" begin
@test joinpath(S("")) == ""
@test joinpath(S("foo")) == "foo"
@test joinpath(S("foo"), S("bar")) == "foo$(sep)bar"
@test joinpath(S("foo"), S("bar"), S("baz")) == "foo$(sep)bar$(sep)baz"
@test joinpath(S("foo"), S(""), S("baz")) == "foo$(sep)baz"
@test joinpath(S("foo"), S(""), S("")) == "foo$(sep)"
@test joinpath(S("foo"), S(""), S(""), S("bar")) == "foo$(sep)bar"
@test joinpath(S("foo"), S(homedir())) == homedir()
@test joinpath(S(abspath("foo")), S(homedir())) == homedir()
for str in map(S, [sep, "a$(sep)b", "a$(sep)b$(sep)c", "a$(sep)b$(sep)c$(sep)d"])
@test str == joinpath(splitpath(str))
@test joinpath(splitpath(str)) == joinpath(splitpath(str)...)
end
if Sys.iswindows()
@test joinpath(S("foo"),S("D:bar")) == "D:bar"
@test joinpath(S("C:"),S("foo"),S("D:"),S("bar")) == "D:bar"
@test joinpath(S("C:"),S("foo"),S("D:bar"),S("baz")) == "D:bar$(sep)baz"
# relative folders and case-insensitive drive letters
@test joinpath(S("C:\\a\\b"), S("c:c\\e")) == "C:\\a\\b\\c\\e"
# UNC paths
@test joinpath(S("\\\\server"), S("share")) == "\\\\server\\share"
@test joinpath(S("\\\\server"), S("share"), S("a")) == "\\\\server\\share\\a"
@test joinpath(S("\\\\server\\"), S("share"), S("a")) == "\\\\server\\share\\a"
@test joinpath(S("\\\\server"), S("share"), S("a"), S("b")) == "\\\\server\\share\\a\\b"
@test joinpath(S("\\\\server\\share"),S("a")) == "\\\\server\\share\\a"
@test joinpath(S("\\\\server\\share\\"), S("a")) == "\\\\server\\share\\a"
for str in map(S, ["c:\\", "c:\\a", "c:\\a\\b", "c:\\a\\b\\c", "c:\\a\\b\\c\\d"])
@test str == joinpath(splitpath(str))
@test joinpath(splitpath(str)) == joinpath(splitpath(str)...)
end
elseif Sys.isunix()
@test joinpath(S("foo"),S("bar:baz")) == "foo$(sep)bar:baz"
@test joinpath(S("C:"),S("foo"),S("D:"),S("bar")) == "C:$(sep)foo$(sep)D:$(sep)bar"
@test joinpath(S("C:"),S("foo"),S("D:"),S("bar"),S("baz")) == "C:$(sep)foo$(sep)D:$(sep)bar$(sep)baz"
end
end
@testset "normpath" begin
@test normpath(S(joinpath("."))) == "."
@test normpath(S(joinpath(".."))) == ".."
@test normpath(S(joinpath("..","."))) == ".."
@test normpath(S(joinpath(".",".."))) == ".."
@test normpath(S(joinpath("..",".."))) == "..$(sep).."
@test normpath(S(joinpath(".","..",".."))) == "..$(sep).."
@test normpath(S(joinpath("..",".",".."))) == "..$(sep).."
@test normpath(S(joinpath("..","..","."))) == "..$(sep).."
@test normpath(S(joinpath("foo","."))) == "foo$sep"
@test normpath(S(joinpath("foo",".."))) == "."
@test normpath(S(joinpath("foo","..","."))) == "."
@test normpath(S(joinpath("foo",".",".."))) == "."
@test normpath(S(joinpath("foo","..",".."))) == ".."
@test normpath(S(joinpath("foo",".","..",".."))) == ".."
@test normpath(S(joinpath("foo","..",".",".."))) == ".."
@test normpath(S(joinpath("foo","..","..","."))) == ".."
@test normpath(S(joinpath(".","bar"))) == "bar"
@test normpath(S(joinpath("..","bar"))) == "..$(sep)bar"
@test normpath(S(joinpath("..",".","bar"))) == "..$(sep)bar"
@test normpath(S(joinpath(".","..","bar"))) == "..$(sep)bar"
@test normpath(S(joinpath("..","..","bar"))) == "..$(sep)..$(sep)bar"
@test normpath(S(joinpath(".","..","..","bar"))) == "..$(sep)..$(sep)bar"
@test normpath(S(joinpath("..",".","..","bar"))) == "..$(sep)..$(sep)bar"
@test normpath(S(joinpath("..","..",".","bar"))) == "..$(sep)..$(sep)bar"
@test normpath(S(joinpath("foo",".","bar"))) == "foo$(sep)bar"
@test normpath(S(joinpath("foo","..","bar"))) == "bar"
@test normpath(S(joinpath("foo","..",".","bar"))) == "bar"
@test normpath(S(joinpath("foo",".","..","bar"))) == "bar"
@test normpath(S(joinpath("foo","..","..","bar"))) == "..$(sep)bar"
@test normpath(S(joinpath("foo",".","..","..","bar"))) == "..$(sep)bar"
@test normpath(S(joinpath("foo","..",".","..","bar"))) == "..$(sep)bar"
@test normpath(S(joinpath("foo","..","..",".","bar"))) == "..$(sep)bar"
@test normpath(normpath(S(joinpath("a", "..", "b", ".", "c")))) == normpath(S(joinpath("a", "..", "b", ".", "c")))
end
@test relpath(S(joinpath("foo","bar")), S("foo")) == "bar"
@testset "splitpath" begin
@test splitpath(S(joinpath("a","b","c"))) == ["a", "b", "c"]
@test splitpath("") == [""]
@test splitpath(S(joinpath("cats are", "gr8t"))) == ["cats are", "gr8t"]
@test splitpath(S(joinpath(" ", " "))) == [" ", " "]
# Unix-style paths are understood by all systems.
@test splitpath(S("/a/b")) == ["/", "a", "b"]
@test splitpath(S("/")) == ["/"]
@test splitpath(S("a/")) == ["a"]
@test splitpath(S("a/b/")) == ["a", "b"]
@test splitpath(S("a.dir/b.txt")) == ["a.dir", "b.txt"]
@test splitpath(S("///")) == ["/"]
@test splitpath(S("///a///b///")) == ["/", "a", "b"]
if Sys.iswindows()
@test splitpath(S("C:\\\\a\\b\\c")) == ["C:\\", "a", "b", "c"]
@test splitpath(S("C:\\\\")) == ["C:\\"]
@test splitpath(S("J:\\")) == ["J:\\"]
@test splitpath(S("C:")) == ["C:"]
@test splitpath(S("C:a")) == ["C:a"]
@test splitpath(S("C:a\\b")) == ["C:a", "b"]
@test splitpath(S("a\\")) == ["a"]
@test splitpath(S("a\\\\b\\\\")) == ["a","b"]
@test splitpath(S("a.dir\\b.txt")) == ["a.dir", "b.txt"]
@test splitpath(S("\\a\\b\\")) == ["\\", "a","b"]
@test splitpath(S("\\\\a\\b")) == ["\\\\a\\b"] # This is actually a valid drive name in windows.
@test splitpath(S("/a/b\\c/d\\\\e")) == ["/", "a", "b", "c", "d", "e"]
@test splitpath(S("/\\/\\")) == ["/"]
@test splitpath(S("\\/\\a/\\//b")) == ["\\","a","b"]
end
end
@testset "splitdir, splitdrive, splitext" begin
@test joinpath(splitdir(S(homedir()))...) == homedir()
@test string(splitdrive(S(homedir()))...) == homedir()
@test splitdrive("a\nb") == ("", "a\nb")
@test splitdir("a/\xfe/\n/b/c.ext") == ("a/\xfe/\n/b", "c.ext")
@test splitext("a/\xfe/\n/b/c.ext") == ("a/\xfe/\n/b/c", ".ext")
if Sys.iswindows()
@test splitdrive(S("\\\\servername\\hello.world\\filename.ext")) ==
("\\\\servername\\hello.world","\\filename.ext")
@test splitdrive(S("\\\\servername.com\\hello.world\\filename.ext")) ==
("\\\\servername.com\\hello.world","\\filename.ext")
@test splitdrive(S("C:\\foo\\bar")) ==
("C:","\\foo\\bar")
# only single characters followed by a colon are drives
@test splitdrive(S("foo:bar")) ==
("", "foo:bar")
# unicode
@test splitdrive(S("\\\\α\\β\\γ")) == ("\\\\α\\β", "\\γ")
@test splitdrive(S("\\\\?\\UNC\\α\\β\\γ")) == ("\\\\?\\UNC\\α\\β", "\\γ")
# splitdrive currently allows any single codeunit char except separators as drive letters
# while isabspath does not allow this. FIXME?
@test splitdrive(S("::")) == ("::", "")
@test splitdrive(S("🍎:")) != ("🍎:", "")
# The behavior is different for long baths, where he drive letter can
# contain multiple codeunits (such as unicode chars or multiple chars)
# if it is followed by a delimiter, because it is then captured as a
# UNC path with the server name ?. FIXME?
@test splitdrive(S("\\\\?\\🍎:\\foobar")) == ("\\\\?\\🍎:", "\\foobar")
@test splitdrive(S("\\\\?\\CC:\\foobar")) == ("\\\\?\\CC:", "\\foobar")
# If the path contains no delimiters after the path however,
# everything goes into the drive
@test splitdrive("\\\\?\\🍎:foobar") == ("\\\\?\\🍎:foobar", "")
end
@test splitdir(S("foo")) == ("", "foo")
@test splitdir(S("foo/")) == ("foo", "")
@test splitdir(S("/foo")) == ("/", "foo")
@test splitdir(S("/foo/")) == ("/foo", "")
@test splitdir(S("foo/bar")) == ("foo", "bar")
@test splitdir(S("/foo/bar")) == ("/foo", "bar")
@test splitdir(S("/foo/bar/")) == ("/foo/bar", "")
@test splitdir(S("/foo/bar/baz")) == ("/foo/bar", "baz")
@test splitdir(S("/foo/bar/baz/")) == ("/foo/bar/baz", "")
@test splitdir(S("foo/bar/baz/")) == ("foo/bar/baz", "")
# Multiple leading separators are reduced to one only when
# all separators are at the beginning. FIXME?
@test splitdir(S("///foo")) == ("/", "foo") # why not ("///", "foo") ?
@test splitdir(S("///foo/bar")) == ("///foo", "bar")
if Sys.iswindows()
@test splitdir(S("/\\foo")) == ("/", "foo") # why not ("/\\", "foo") ?
@test splitdir(S("\\/foo")) == ("\\", "foo") # why not ("\\/", "foo") ?
@test splitdir(S("/\\/foo/bar")) == ("/\\/foo", "bar")
@test splitdir(S("///foo/bar/")) == ("///foo/bar", "")
@test splitdir(S("C:")) == ("C:", "")
@test splitdir(S("C:\\")) == ("C:\\", "")
@test splitdir(S("C:\\foo")) == ("C:\\", "foo")
@test splitdir(S("C:\\foo\\bar")) == ("C:\\foo", "bar")
@test splitdir(S("\\\\?\\C:\\foo\\bar")) == ("\\\\?\\C:\\foo", "bar")
@test splitdir(S("\\\\?\\C:\\foo\\bar\\")) == ("\\\\?\\C:\\foo\\bar", "")
end
@test splitext(S("")) == ("", "")
@test splitext(S(".")) == (".", "")
@test_broken splitext(S("..")) == ("..", "")
@test_broken splitext(S("...")) == ("...", "")
@test splitext(S("foo")) == ("foo", "")
@test splitext(S("foo.")) == ("foo", ".")
@test_broken splitext(S("foo..")) == ("foo", "..")
@test_broken splitext(S("foo...")) == ("foo", "...")
@test splitext(S("foo.bar")) == ("foo", ".bar")
@test splitext(S(".foo")) == (".foo", "")
@test splitext(S(".foo.")) == (".foo", ".")
@test_broken splitext(S(".foo..")) == (".foo", "..")
@test_broken splitext(S(".foo...")) == (".foo", "...")
@test splitext(S(".foo.bar")) == (".foo", ".bar")
@test splitext(S("bar/.foo/baz")) == ("bar/.foo/baz", "")
@test splitext(S("bar/foo/.baz")) == ("bar/foo/.baz", "")
@test splitext(S("bar/foo.baz")) == ("bar/foo", ".baz")
# Before merging https://github.com/JuliaLang/julia/pull/60677,
# a single \n would be removed from the first output unless that made
# it empty or end with a separator. The tests below reflect the
# updated behavior.
@test splitext(S("a\r\n")) == ("a\r\n", "")
@test splitext(S("a/\n")) == ("a/\n", "") # not changed by 60677
@test splitext(S("a\n.foo")) == ("a\n", ".foo")
@test splitext(S("a/\n.foo")) == ("a/\n", ".foo")
@test splitext(S("\n")) == ("\n", "") # not changed by 60677
if Sys.iswindows()
@test splitext(S("C:a\n")) == ("C:a\n", "")
@test splitext(S("C:\n")) == ("C:\n", "") # not changed by 60677
end
end
@testset "isabspath" begin
@test isabspath(S("~")) == false
@test isabspath(S("/")) == true # on windows, this is relatively absolute
@test isabspath(S("A:/")) == Sys.iswindows()
@test isabspath(S("B:\\")) == Sys.iswindows()
@test isabspath(S("./")) == false
@test isabspath(S("C:")) == false
@test isabspath(S("C:.")) == false
@test isabspath(S("α:/")) == false
@test isabspath(S(".:/")) == false
#@test isabspath(S("_:/")) == false # FIXME?
#@test isabspath(S("AB:/")) == false # FIXME?
@test isabspath(S("\\\\")) == Sys.iswindows()
@test isabspath(S(expanduser("~"))) == true
@test startswith(expanduser(S("~")), homedir())
if Sys.iswindows()
@test isabspath(S("\\\\?\\C:\\"))
# Current behavior is to allow anything starting with a separator,
# even if this is not a long path, nor a UNC path.
@test isabspath(S("///a/b/"))
# Drive letters are currently treated differently in long path format. FIXME?
@test isabspath(S("\\\\?\\α:\\")) != isabspath("α:\\")
end
end
@testset "relpath" begin
function test_relpath()
sep = Base.Filesystem.path_separator
filepaths = [
"$(sep)home$(sep)user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)Test1.md",
"$(sep)home$(sep)user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)lib$(sep)file1.md",
"$(sep)home$(sep)user$(sep).julia$(sep)测试2$(sep)docs$(sep)api$(sep)测试2.md",
"$(sep)home$(sep)user$(sep)dir_withendsep$(sep)",
"$(sep)home$(sep)dir2_withendsep$(sep)",
"$(sep)home$(sep)test.md",
"$(sep)home",
# Special cases
"$(sep)",
"$(sep)home$(sep)$(sep)$(sep)"
]
startpaths = [
"$(sep)home$(sep)user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)genindex.md",
"$(sep)multi_docs$(sep)genindex.md",
"$(sep)home$(sep)user$(sep)dir_withendsep$(sep)",
"$(sep)home$(sep)dir2_withendsep$(sep)",
"$(sep)home$(sep)test.md",
"$(sep)home",
# Special cases
"$(sep)",
"$(sep)home$(sep)$(sep)$(sep)"
]
relpath_expected_results = [
"..$(sep)Test1.md",
"..$(sep)..$(sep)home$(sep)user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)Test1.md",
"..$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)Test1.md",
"..$(sep)user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)Test1.md",
"..$(sep)user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)Test1.md",
"user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)Test1.md",
"home$(sep)user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)Test1.md",
"user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)Test1.md",
"..$(sep)lib$(sep)file1.md",
"..$(sep)..$(sep)home$(sep)user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)lib$(sep)file1.md",
"..$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)lib$(sep)file1.md",
"..$(sep)user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)lib$(sep)file1.md",
"..$(sep)user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)lib$(sep)file1.md",
"user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)lib$(sep)file1.md",
"home$(sep)user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)lib$(sep)file1.md",
"user$(sep).julia$(sep)Test1$(sep)docs$(sep)api$(sep)lib$(sep)file1.md",
"..$(sep)..$(sep)..$(sep)..$(sep)测试2$(sep)docs$(sep)api$(sep)测试2.md",
"..$(sep)..$(sep)home$(sep)user$(sep).julia$(sep)测试2$(sep)docs$(sep)api$(sep)测试2.md",
"..$(sep).julia$(sep)测试2$(sep)docs$(sep)api$(sep)测试2.md",
"..$(sep)user$(sep).julia$(sep)测试2$(sep)docs$(sep)api$(sep)测试2.md",
"..$(sep)user$(sep).julia$(sep)测试2$(sep)docs$(sep)api$(sep)测试2.md",
"user$(sep).julia$(sep)测试2$(sep)docs$(sep)api$(sep)测试2.md",
"home$(sep)user$(sep).julia$(sep)测试2$(sep)docs$(sep)api$(sep)测试2.md",
"user$(sep).julia$(sep)测试2$(sep)docs$(sep)api$(sep)测试2.md",
"..$(sep)..$(sep)..$(sep)..$(sep)..$(sep)dir_withendsep",
"..$(sep)..$(sep)home$(sep)user$(sep)dir_withendsep",".","..$(sep)user$(sep)dir_withendsep",
"..$(sep)user$(sep)dir_withendsep","user$(sep)dir_withendsep",
"home$(sep)user$(sep)dir_withendsep","user$(sep)dir_withendsep",
"..$(sep)..$(sep)..$(sep)..$(sep)..$(sep)..$(sep)dir2_withendsep",
"..$(sep)..$(sep)home$(sep)dir2_withendsep","..$(sep)..$(sep)dir2_withendsep",".",
"..$(sep)dir2_withendsep","dir2_withendsep","home$(sep)dir2_withendsep","dir2_withendsep",
"..$(sep)..$(sep)..$(sep)..$(sep)..$(sep)..$(sep)test.md","..$(sep)..$(sep)home$(sep)test.md",
"..$(sep)..$(sep)test.md","..$(sep)test.md",".","test.md","home$(sep)test.md","test.md",
"..$(sep)..$(sep)..$(sep)..$(sep)..$(sep)..","..$(sep)..$(sep)home","..$(sep)..",
"..","..",".","home",".","..$(sep)..$(sep)..$(sep)..$(sep)..$(sep)..$(sep)..","..$(sep)..",
"..$(sep)..$(sep)..","..$(sep)..","..$(sep)..","..",".","..",
"..$(sep)..$(sep)..$(sep)..$(sep)..$(sep)..","..$(sep)..$(sep)home","..$(sep)..",
"..","..",".","home","."
]
idx = 0
for filep in filepaths
for startp in startpaths
res = relpath(filep, startp)
idx += 1
@test res == relpath_expected_results[idx]
if Sys.iswindows()
@test relpath("e:$filep", "e:$startp") == relpath_expected_results[idx]
@test relpath("e:$filep", "E:$startp") == relpath_expected_results[idx]
@test relpath("E:$filep", "e:$startp") == relpath_expected_results[idx]
@test relpath("E:$filep", "E:$startp") == relpath_expected_results[idx]
end
end
end
# Additional cases
@test_throws ArgumentError relpath(S("$(sep)home$(sep)user$(sep)dir_withendsep$(sep)"), "")
@test_throws ArgumentError relpath(S(""), S("$(sep)home$(sep)user$(sep)dir_withendsep$(sep)"))
# issue 40237
path = "..$(sep)a$(sep)b$(sep)c"
@test relpath(abspath(path)) == path
end
test_relpath()
end
@testset "uripath" begin
host = if Sys.iswindows()
""
elseif Sys.detectwsl()
distro = get(ENV, "WSL_DISTRO_NAME", "") # See <https://patrickwu.space/wslconf/>
"wsl%24/$distro" # See <https://github.com/microsoft/terminal/pull/14993> and <https://learn.microsoft.com/en-us/windows/wsl/filesystems>
else
gethostname()
end
sysdrive, uridrive = if Sys.iswindows() "C:\\", "C:/" else "/", "" end
@test Base.Filesystem.uripath("$(sysdrive)some$(sep)file.txt") == "file://$host/$(uridrive)some/file.txt"
@test Base.Filesystem.uripath("$(sysdrive)another$(sep)$(sep)folder$(sep)file.md") == "file://$host/$(uridrive)another/folder/file.md"
@test Base.Filesystem.uripath("$(sysdrive)some file with ^odd% chars") == "file://$host/$(uridrive)some%20file%20with%20%5Eodd%25%20chars"
@test Base.Filesystem.uripath("$(sysdrive)weird chars like @#&()[]{}") == "file://$host/$(uridrive)weird%20chars%20like%20%40%23%26%28%29%5B%5D%7B%7D"
@test Base.Filesystem.uripath("$sysdrive") == "file://$host/$uridrive"
@test Base.Filesystem.uripath(".") == Base.Filesystem.uripath(pwd())
@test Base.Filesystem.uripath("$(sysdrive)unicode$(sep)Δεδομένα") == "file://$host/$(uridrive)unicode/%CE%94%CE%B5%CE%B4%CE%BF%CE%BC%CE%AD%CE%BD%CE%B1"
@test Base.Filesystem.uripath("$(sysdrive)unicode$(sep)🧮🐛🔨") == "file://$host/$(uridrive)unicode/%F0%9F%A7%AE%F0%9F%90%9B%F0%9F%94%A8"
end
if Sys.iswindows()
@testset "issue #23646" begin
@test lowercase(relpath("E:\\a\\b", "C:\\c")) == "e:\\a\\b"
@test lowercase(relpath("E:\\a\\b", "c:\\c")) == "e:\\a\\b"
@test lowercase(relpath("e:\\a\\b", "C:\\c")) == "e:\\a\\b"
@test lowercase(relpath("e:\\a\\b", "c:\\c")) == "e:\\a\\b"
@test relpath("C:\\a\\b", "c:\\a\\b") == "."
@test relpath("c:\\a\\b", "C:\\a\\b") == "."
@test lowercase(relpath("C:\\a\\b", "c:\\c\\d")) == "..\\..\\a\\b"
@test lowercase(relpath("c:\\a\\b", "C:\\c\\d")) == "..\\..\\a\\b"
end
end
@testset "type stability" begin
@test isa(joinpath(S("a"), S("b")), String)
@test isa(joinpath(S(abspath("a")), S("b")), String)
end
@testset "Separator" begin
@test Base.Filesystem.isseparator('/')
@test any(Base.Filesystem.isseparator, "abc/def")
@test occursin(Base.Filesystem.path_separator_re, "abc/def")
@test !Base.Filesystem.isseparator('a')
@test !any(Base.Filesystem.isseparator, "abcdef")
@test !occursin(Base.Filesystem.path_separator_re, "abcdef")
if Sys.iswindows()
@test Base.Filesystem.isseparator('\\')
@test any(Base.Filesystem.isseparator, "abc\\def")
@test occursin(Base.Filesystem.path_separator_re, "abc\\def")
end
end
end
@testset "homedir" begin
var = Sys.iswindows() ? "USERPROFILE" : "HOME"
AVG_PATH = Base.Filesystem.AVG_PATH - 1 # null-termination character
for i = 0:9
local home = " "^AVG_PATH * "123456789"[1:i]
@test withenv(var => home) do
homedir()
end == home
end
@test isabspath(withenv(homedir, var => nothing))
# homedir(username) returns a directory for the current user
me = Sys.username()
me_home = homedir(me)
@test me_home !== nothing
@test isdir(me_home)
@test isabspath(me_home)
# non-existent user returns nothing
nouser = "nouser_" * randstring(12)
@test homedir(nouser) === nothing
end