require "spec" require "./spec_helper" require "../support/env" private HOME_ENV_KEY = {% if flag?(:win32) %} "USERPROFILE" {% else %} "HOME" {% end %} private BASE_POSIX = "/default/base" private BASE_WINDOWS = "\\default\\base" private HOME_WINDOWS = "C:\\Users\\Crystal" private HOME_POSIX = "/home/crystal" private def it_normalizes_path(path, posix = path, windows = path, file = __FILE__, line = __LINE__) assert_paths(path, posix, windows, "normalizes", file, line, &.normalize) end private def it_expands_path(path, posix, windows = posix, *, base = nil, env_home = nil, expand_base = false, home = false, file = __FILE__, line = __LINE__) assert_paths(path, posix, windows, %((base: "#{base}")), file, line) do |path| with_env({HOME_ENV_KEY => env_home}) do base_arg = base || (path.windows? ? BASE_WINDOWS : BASE_POSIX) base_arg = path.windows? ? Path.windows(base_arg) : Path.posix(base_arg) unless base_arg.is_a?(Path) if home == true && env_home.nil? myhome = path.windows? ? Path.windows(HOME_WINDOWS) : Path.posix(HOME_POSIX) else myhome = home end path.expand(base_arg, expand_base: !!expand_base, home: myhome) end end end private def it_joins_path(path, parts, posix, windows = posix, file = __FILE__, line = __LINE__) assert_paths(path, posix, windows, %(resolving "#{parts}"), file, line, &.join(parts)) unless parts.is_a?(Enumerable) # FIXME: Omitting the type cast results in Error: can't infer block return type, try to cast the block body with `as`. assert_paths(path, posix, windows, %(resolving ["#{parts}"] ), file, line, &.join([parts]).as(Path)) assert_paths(path, posix, windows, %(resolving ["#{parts}"].each), file, line, &.join([parts].each).as(Path)) end end private def assert_paths(path, posix, windows = posix, label = nil, file = __FILE__, line = __LINE__, &block : Path -> _) case posix when Nil when Tuple then posix = Path.posix(*posix) when String then posix = Path.posix(posix) when Array then posix = posix.map { |path| Path.posix(path) } end case windows when Nil when Tuple then windows = Path.windows(*windows) when String then windows = Path.windows(windows) when Array then windows = windows.map { |path| Path.windows(path) } end assert_paths_raw(path, posix, windows, label, file, line, &block) end private def assert_paths_raw(path, posix, windows = posix, label = nil, file = __FILE__, line = __LINE__, &block : Path -> _) it %(#{label} "#{path}" (posix)), file, line do block.call(Path.posix(path)).should eq(posix), file: file, line: line end it %(#{label} "#{path}" (windows)), file, line do block.call(Path.windows(path)).should eq(windows), file: file, line: line end end private def it_relativizes(base, target, posix, windows = posix, file = __FILE__, line = __LINE__) assert_paths target, posix, windows, %(on "#{base}":), file, line do |path| path.relative_to?(base) end end private def it_iterates_parts(path, posix, windows = posix, file = __FILE__, line = __LINE__) assert_paths_raw path, posix, windows, label: "block", file: file, line: line do |path| array = [] of String path.each_part do |part| array << part end array end assert_paths_raw path, posix, windows, label: "iterator", file: file, line: line do |path| array = [] of String path.each_part.each do |part| array << part end array end assert_paths_raw path, posix, windows, label: "#parts", file: file, line: line do |path| path.parts end end describe Path do describe ".new" do it { Path.new("foo").native?.should be_true } it { Path.new("foo").to_s.should eq "foo" } it "fails with null byte" do expect_raises ArgumentError, "String contains null byte" do Path.new("foo\0") end end it { Path.new.to_s.should eq "" } it "joins components" do Path.new("foo", "bar").should eq Path.new("foo").join("bar") Path.new(Path.new("foo"), "bar").should eq Path.new("foo", "bar") Path.new(Path.posix("foo"), "bar").should eq Path.new("foo", "bar") Path.new(Path.windows("foo"), "bar").should eq Path.new("foo", "bar") # implicit conversion: Path.windows("foo", Path.posix("bar\\baz")).should eq Path.windows("foo").join(Path.posix("bar\\baz").to_windows) end end describe ".posix" do it { Path.posix("foo").posix?.should be_true } it { Path.posix("foo").windows?.should be_false } it { Path.posix("foo").to_s.should eq "foo" } it "fails with null byte" do expect_raises ArgumentError, "String contains null byte" do Path.posix("foo\0") end end it { Path.posix.to_s.should eq "" } it "joins components" do Path.posix("foo", "bar").should eq Path.posix("foo").join("bar") Path.posix(Path.new("foo"), "bar").should eq Path.posix("foo", "bar") Path.posix(Path.posix("foo"), "bar").should eq Path.posix("foo", "bar") Path.posix(Path.windows("foo"), "bar").should eq Path.posix("foo", "bar") end end describe ".windows" do it { Path.windows("foo").posix?.should be_false } it { Path.windows("foo").windows?.should be_true } it { Path.windows("foo").to_s.should eq "foo" } it "fails with null byte" do expect_raises ArgumentError, "String contains null byte" do Path.windows("foo\0") end end it { Path.windows.to_s.should eq "" } it "joins components" do Path.windows("foo", "bar").should eq Path.windows("foo").join("bar") Path.windows(Path.new("foo"), "bar").should eq Path.windows("foo", "bar") Path.windows(Path.posix("foo"), "bar").should eq Path.windows("foo", "bar") Path.windows(Path.windows("foo"), "bar").should eq Path.windows("foo", "bar") end end it ".[]" do Path["foo"].should eq Path.new("foo") Path["foo"].native?.should be_true Path["foo", "bar", "baz"].should eq Path.new("foo", "bar", "baz") Path["/foo", "bar", "baz"].should eq Path.new("/foo", "bar", "baz") end describe "#parent" do assert_paths("/Users/foo/bar.cr", "/Users/foo", &.parent) assert_paths("Users/foo/bar.cr", "Users/foo", &.parent) assert_paths("foo/bar/", "foo", &.parent) assert_paths("foo/bar/.", "foo/bar", &.parent) assert_paths("foo/bar/..", "foo/bar", &.parent) assert_paths("foo", ".", &.parent) assert_paths("foo/", ".", &.parent) assert_paths("/", "/", &.parent) assert_paths("/.", "/", &.parent) assert_paths("////", "/", &.parent) assert_paths("foo//.//", "foo", &.parent) assert_paths("/.", "/", &.parent) assert_paths("/foo", "/", &.parent) assert_paths("", ".", &.parent) assert_paths("./foo", ".", &.parent) assert_paths(".", ".", &.parent) assert_paths("\\Users\\foo\\bar.cr", ".", "\\Users\\foo", &.parent) assert_paths("\\Users/foo\\bar.cr", "\\Users", "\\Users/foo", &.parent) assert_paths("foo\\bar\\", ".", "foo", &.parent) assert_paths("foo\\bar\\.", ".", "foo\\bar", &.parent) assert_paths("foo\\bar\\..", ".", "foo\\bar", &.parent) assert_paths("foo\\", ".", &.parent) assert_paths("\\", ".", "\\", &.parent) assert_paths("\\.", ".", "\\", &.parent) assert_paths(".\\foo", ".", &.parent) assert_paths("C:", ".", "C:", &.parent) assert_paths("C:/", ".", "C:/", &.parent) assert_paths("C:\\", ".", "C:\\", &.parent) assert_paths("C:/foo", "C:", "C:/", &.parent) assert_paths("C:\\foo", ".", "C:\\", &.parent) assert_paths("\\\\.", ".", "\\\\.", &.parent) assert_paths("\\/?", "\\", "\\/?", &.parent) assert_paths("//.", "/", "//.", &.parent) assert_paths("//./", "/", "//./", &.parent) assert_paths("//.\\", "/", "//.\\", &.parent) assert_paths("//./foo", "//.", "//./", &.parent) assert_paths("//.\\foo", "/", "//.\\", &.parent) assert_paths("//?/", "/", "//?/", &.parent) assert_paths("//?\\", "/", "//?\\", &.parent) assert_paths("//?/foo", "//?", "//?/", &.parent) assert_paths("//?\\foo", "/", "//?\\", &.parent) assert_paths("\\\\?/", ".", "\\\\?/", &.parent) assert_paths("\\\\?\\", ".", "\\\\?\\", &.parent) assert_paths("/foo/C:/bar", "/foo/C:", "/foo/C:", &.parent) assert_paths("//some/share", "//some", "//some/share", &.parent) assert_paths("//some/share/", "//some", "//some/share/", &.parent) assert_paths("//some/share/a", "//some/share", "//some/share/", &.parent) assert_paths("//some/share/a/", "//some/share", "//some/share/", &.parent) end describe "#parents" do assert_paths("/Users/foo/bar.cr", ["/", "/Users", "/Users/foo"], &.parents) assert_paths("Users/foo/bar.cr", [".", "Users", "Users/foo"], &.parents) assert_paths("foo/bar/", [".", "foo"], &.parents) assert_paths("foo/bar/.", [".", "foo", "foo/bar"], &.parents) assert_paths("foo", ["."], &.parents) assert_paths("foo/", ["."], &.parents) assert_paths("/", [] of String, &.parents) assert_paths("////", [] of String, &.parents) assert_paths("/.", ["/"], &.parents) assert_paths("/foo", ["/"], &.parents) assert_paths("", [] of String, &.parents) assert_paths("./foo", ["."], &.parents) assert_paths(".", [] of String, &.parents) assert_paths("\\Users\\foo\\bar.cr", ["."], ["\\", "\\Users", "\\Users\\foo"], &.parents) assert_paths("\\Users/foo\\bar.cr", [".", "\\Users"], ["\\", "\\Users", "\\Users/foo"], &.parents) assert_paths("C:\\Users\\foo\\bar.cr", ["."], ["C:\\", "C:\\Users", "C:\\Users\\foo"], &.parents) assert_paths("foo\\bar\\", ["."], [".", "foo"], &.parents) assert_paths("foo\\", ["."], &.parents) assert_paths("\\", ["."], [] of String, &.parents) assert_paths(".\\foo", ["."], &.parents) assert_paths("foo/../bar/", [".", "foo", "foo/.."], &.parents) assert_paths("foo/../bar/.", [".", "foo", "foo/..", "foo/../bar"], &.parents) assert_paths("foo/bar/..", [".", "foo", "foo/bar"], &.parents) assert_paths("foo/bar/../.", [".", "foo", "foo/bar", "foo/bar/.."], &.parents) assert_paths("foo/./bar/", [".", "foo", "foo/."], &.parents) assert_paths("foo/./bar/.", [".", "foo", "foo/.", "foo/./bar"], &.parents) assert_paths("foo/bar/.", [".", "foo", "foo/bar"], &.parents) assert_paths("foo/bar/./.", [".", "foo", "foo/bar", "foo/bar/."], &.parents) assert_paths("m/.gitignore", [".", "m"], &.parents) assert_paths("m", ["."], &.parents) assert_paths("m/", ["."], &.parents) assert_paths("m//", ["."], &.parents) assert_paths("m//a/b", [".", "m", "m//a"], &.parents) assert_paths("/m", ["/"], &.parents) assert_paths("/m/", ["/"], &.parents) assert_paths("C:", ["."], [] of String, &.parents) assert_paths("C:/", ["."], [] of String, &.parents) assert_paths("C:\\", ["."], [] of String, &.parents) assert_paths("C:folder", ["."], ["C:"], &.parents) assert_paths("C:\\folder", ["."], ["C:\\"], &.parents) assert_paths("C:\\\\folder", ["."], ["C:\\\\"], &.parents) assert_paths("C:\\.", ["."], ["C:\\"], &.parents) assert_paths("\\\\.", ["."], [] of String, &.parents) assert_paths("\\/?", [".", "\\"], [] of String, &.parents) assert_paths("//.", ["//"], [] of String, &.parents) assert_paths("//./", ["//"], [] of String, &.parents) assert_paths("//.\\", ["//"], [] of String, &.parents) assert_paths("//./foo", ["//", "//."], ["//./"], &.parents) assert_paths("//.\\foo", ["//"], ["//.\\"], &.parents) assert_paths("//?/", ["//"], [] of String, &.parents) assert_paths("//?\\", ["//"], [] of String, &.parents) assert_paths("//?/foo", ["//", "//?"], ["//?/"], &.parents) assert_paths("//?\\foo", ["//"], ["//?\\"], &.parents) assert_paths("\\\\?/", ["."], [] of String, &.parents) assert_paths("\\\\?\\", ["."], [] of String, &.parents) assert_paths("//some/share", ["//", "//some"], [] of String, &.parents) assert_paths("//some/share/", ["//", "//some"], [] of String, &.parents) assert_paths("//some/share/a", ["//", "//some", "//some/share"], ["//some/share/"], &.parents) assert_paths("//some/share/a/", ["//", "//some", "//some/share"], ["//some/share/"], &.parents) end describe "#dirname" do assert_paths_raw("/Users/foo/bar.cr", "/Users/foo", &.dirname) assert_paths_raw("foo", ".", &.dirname) assert_paths_raw("foo/", ".", &.dirname) assert_paths_raw("/foo", "/", &.dirname) assert_paths_raw("/foo/", "/", &.dirname) assert_paths_raw("/foo//", "/", &.dirname) assert_paths_raw("m/.gitignore", "m", &.dirname) assert_paths_raw("m/", ".", &.dirname) assert_paths_raw("m//", ".", &.dirname) assert_paths_raw("m//a/b", "m//a", &.dirname) assert_paths_raw("m", ".", &.dirname) assert_paths_raw("/m", "/", &.dirname) assert_paths_raw("/m/", "/", &.dirname) assert_paths_raw("C:", ".", "C:", &.dirname) assert_paths_raw("C:/", ".", "C:/", &.dirname) assert_paths_raw("C:\\", ".", "C:\\", &.dirname) assert_paths_raw("C:/foo", "C:", "C:/", &.dirname) assert_paths_raw("C:\\foo", ".", "C:\\", &.dirname) assert_paths_raw("\\\\.", ".", "\\\\.", &.dirname) assert_paths_raw("\\/?", "\\", "\\/?", &.dirname) assert_paths_raw("//.", "/", "//.", &.dirname) assert_paths_raw("//./", "/", "//./", &.dirname) assert_paths_raw("//.\\", "/", "//.\\", &.dirname) assert_paths_raw("//./foo", "//.", "//./", &.dirname) assert_paths_raw("//.\\foo", "/", "//.\\", &.dirname) assert_paths_raw("//?/", "/", "//?/", &.dirname) assert_paths_raw("//?\\", "/", "//?\\", &.dirname) assert_paths_raw("//?/foo", "//?", "//?/", &.dirname) assert_paths_raw("//?\\foo", "/", "//?\\", &.dirname) assert_paths_raw("\\\\?/", ".", "\\\\?/", &.dirname) assert_paths_raw("\\\\?\\", ".", "\\\\?\\", &.dirname) assert_paths_raw("//some/share", "//some", "//some/share", &.dirname) assert_paths_raw("//some/share/", "//some", "//some/share/", &.dirname) assert_paths_raw("//some/share/a", "//some/share", "//some/share/", &.dirname) assert_paths_raw("//some/share/a/", "//some/share", "//some/share/", &.dirname) end describe "#basename" do assert_paths_raw("/foo/bar/baz.cr", "baz.cr", &.basename) assert_paths_raw("/foo/", "foo", &.basename) assert_paths_raw("foo", "foo", &.basename) assert_paths_raw("x", "x", &.basename) assert_paths_raw("", "", &.basename) assert_paths_raw(".", ".", &.basename) assert_paths_raw("/.", ".", &.basename) assert_paths_raw("/", "/", &.basename) assert_paths_raw("////", "/", &.basename) assert_paths_raw("a/x", "x", &.basename) assert_paths_raw("a/.x", ".x", &.basename) assert_paths_raw("a/x.", "x.", &.basename) assert_paths_raw("\\foo\\bar\\baz.cr", "\\foo\\bar\\baz.cr", "baz.cr", &.basename) assert_paths_raw("\\foo\\", "\\foo\\", "foo", &.basename) assert_paths_raw("\\", "\\", "\\", &.basename) assert_paths_raw("\\.", "\\.", ".", &.basename) describe "removes suffix" do assert_paths_raw("/foo/bar/baz.cr", "baz", &.basename(".cr")) assert_paths_raw("\\foo\\bar\\baz.cr", "\\foo\\bar\\baz", "baz", &.basename(".cr")) assert_paths_raw("\\foo/bar\\baz.cr", "bar\\baz", "baz", &.basename(".cr")) assert_paths_raw("/foo/bar/baz.cr.tmp", "baz.cr.tmp", "baz.cr.tmp", &.basename(".cr")) assert_paths_raw("\\foo\\bar\\baz.cr.tmp", "\\foo\\bar\\baz.cr.tmp", "baz.cr.tmp", &.basename(".cr")) assert_paths_raw("/foo/bar/baz.cr.tmp", "baz", &.basename(".cr.tmp")) assert_paths_raw("\\foo\\bar\\baz.cr.tmp", "\\foo\\bar\\baz", "baz", &.basename(".cr.tmp")) assert_paths_raw("/foo/bar/baz.cr.tmp", "baz.cr", &.basename(".tmp")) assert_paths_raw("\\foo\\bar\\baz.cr.tmp", "\\foo\\bar\\baz.cr", "baz.cr", &.basename(".tmp")) assert_paths_raw("a.txt", "a", &.basename(".txt")) assert_paths_raw("a.x", "a", &.basename(".x")) end end describe "#each_part" do it_iterates_parts("/Users/foo/bar.cr", ["/", "Users", "foo", "bar.cr"]) it_iterates_parts("Users/foo/bar.cr", ["Users", "foo", "bar.cr"]) it_iterates_parts("foo/bar/", ["foo", "bar"]) it_iterates_parts("foo/bar/.", ["foo", "bar", "."]) it_iterates_parts("foo", ["foo"]) it_iterates_parts("foo/", ["foo"]) it_iterates_parts("/", ["/"]) it_iterates_parts("////", ["////"]) it_iterates_parts("/.", ["/", "."]) it_iterates_parts("/foo", ["/", "foo"]) it_iterates_parts("", [] of String) it_iterates_parts("./foo", [".", "foo"]) it_iterates_parts(".", ["."]) it_iterates_parts("\\Users\\foo\\bar.cr", ["\\Users\\foo\\bar.cr"], ["\\", "Users", "foo", "bar.cr"]) it_iterates_parts("\\Users/foo\\bar.cr", ["\\Users", "foo\\bar.cr"], ["\\", "Users", "foo", "bar.cr"]) it_iterates_parts("C:\\Users\\foo\\bar.cr", ["C:\\Users\\foo\\bar.cr"], ["C:\\", "Users", "foo", "bar.cr"]) it_iterates_parts("\\\\some\\share\\", ["\\\\some\\share\\"], ["\\\\some\\share\\"]) it_iterates_parts("\\\\some\\share", ["\\\\some\\share"]) it_iterates_parts("\\\\some\\share\\bar.cr", ["\\\\some\\share\\bar.cr"], ["\\\\some\\share\\", "bar.cr"]) it_iterates_parts("//some/share", ["//", "some", "share"], ["//some/share"]) it_iterates_parts("//some/share/", ["//", "some", "share"], ["//some/share/"]) it_iterates_parts("//some/share/bar.cr", ["//", "some", "share", "bar.cr"], ["//some/share/", "bar.cr"]) it_iterates_parts("foo\\bar\\", ["foo\\bar\\"], ["foo", "bar"]) it_iterates_parts("foo\\", ["foo\\"], ["foo"]) it_iterates_parts("\\", ["\\"], ["\\"]) it_iterates_parts(".\\foo", [".\\foo"], [".", "foo"]) it_iterates_parts("foo/../bar/", ["foo", "..", "bar"]) it_iterates_parts("foo/../bar/.", ["foo", "..", "bar", "."]) it_iterates_parts("foo/bar/..", ["foo", "bar", ".."]) it_iterates_parts("foo/bar/../.", ["foo", "bar", "..", "."]) it_iterates_parts("foo/./bar/", ["foo", ".", "bar"]) it_iterates_parts("foo/./bar/.", ["foo", ".", "bar", "."]) it_iterates_parts("foo/bar/.", ["foo", "bar", "."]) it_iterates_parts("foo/bar/./.", ["foo", "bar", ".", "."]) it_iterates_parts("m/.gitignore", ["m", ".gitignore"]) it_iterates_parts("m", ["m"]) it_iterates_parts("m/", ["m"]) it_iterates_parts("m//", ["m"]) it_iterates_parts("m\\", ["m\\"], ["m"]) it_iterates_parts("m//a/b", ["m", "a", "b"]) it_iterates_parts("m\\a/b", ["m\\a", "b"], ["m", "a", "b"]) it_iterates_parts("/m", ["/", "m"]) it_iterates_parts("/m/", ["/", "m"]) it_iterates_parts("C:", ["C:"]) it_iterates_parts("C:/", ["C:"], ["C:/"]) it_iterates_parts("C:\\", ["C:\\"]) it_iterates_parts("C:folder", ["C:folder"], ["C:", "folder"]) it_iterates_parts("C:\\folder", ["C:\\folder"], ["C:\\", "folder"]) it_iterates_parts("C:\\\\folder", ["C:\\\\folder"], ["C:\\\\", "folder"]) it_iterates_parts("C:\\.", ["C:\\."], ["C:\\", "."]) it_iterates_parts("//.", ["//", "."], ["//."]) it_iterates_parts("//?", ["//", "?"], ["//?"]) it_iterates_parts("\\\\.\\", ["\\\\.\\"], ["\\\\.\\"]) it_iterates_parts("\\\\?\\", ["\\\\?\\"], ["\\\\?\\"]) it_iterates_parts("\\\\.\\foo", ["\\\\.\\foo"], ["\\\\.\\", "foo"]) it_iterates_parts("\\\\?\\foo", ["\\\\?\\foo"], ["\\\\?\\", "foo"]) it_iterates_parts("\\\\.\\foo\\bar", ["\\\\.\\foo\\bar"], ["\\\\.\\", "foo", "bar"]) it_iterates_parts("\\\\?\\foo\\bar", ["\\\\?\\foo\\bar"], ["\\\\?\\", "foo", "bar"]) end describe "#extension" do assert_paths_raw("/foo/bar/baz.cr", ".cr", &.extension) assert_paths_raw("/foo/bar/baz.cr.cz", ".cz", &.extension) assert_paths_raw("/foo/bar/.profile", "", &.extension) assert_paths_raw("/foo/bar/.profile.sh", ".sh", &.extension) assert_paths_raw("/foo/bar/foo.", "", &.extension) assert_paths_raw("test", "", &.extension) assert_paths_raw("test.ext/foo", "", &.extension) assert_paths_raw("test.ext/foo/", "", &.extension) assert_paths_raw("test.ext/", ".ext", &.extension) assert_paths_raw("test/.", "", &.extension) assert_paths_raw("test\\.", "", &.extension) assert_paths_raw("test.ext\\", ".ext\\", ".ext", &.extension) end describe "#absolute?" do assert_paths_raw("/foo", true, false, &.absolute?) assert_paths_raw("/./foo", true, false, &.absolute?) assert_paths_raw("foo", false, &.absolute?) assert_paths_raw("./foo", false, &.absolute?) assert_paths_raw("~/foo", false, &.absolute?) assert_paths_raw("\\foo", false, &.absolute?) assert_paths_raw("\\.\\foo", false, &.absolute?) assert_paths_raw("foo", false, &.absolute?) assert_paths_raw(".\\foo", false, &.absolute?) assert_paths_raw("~\\foo", false, &.absolute?) assert_paths_raw("C:", false, &.absolute?) assert_paths_raw("C:foo", false, &.absolute?) assert_paths_raw("C:\\foo", false, true, &.absolute?) assert_paths_raw("C:/foo/bar", false, true, &.absolute?) assert_paths_raw("C:\\", false, true, &.absolute?) assert_paths_raw("C:/foo", false, true, &.absolute?) assert_paths_raw("C:/", false, true, &.absolute?) assert_paths_raw("c:\\\\", false, true, &.absolute?) assert_paths_raw("//some/share", true, false, &.absolute?) assert_paths_raw("\\\\some\\share", false, false, &.absolute?) assert_paths_raw("//some/share/", true, true, &.absolute?) assert_paths_raw("\\\\some\\share\\", false, true, &.absolute?) assert_paths_raw("//.", true, false, &.absolute?) assert_paths_raw("\\\\?", false, false, &.absolute?) assert_paths_raw("//./foo", true, true, &.absolute?) assert_paths_raw("\\\\.\\foo", false, true, &.absolute?) assert_paths_raw("//?/foo", true, true, &.absolute?) assert_paths_raw("\\\\?\\foo", false, true, &.absolute?) end describe "#drive" do assert_paths("C:\\foo", nil, "C:", &.drive) assert_paths("C:/foo", nil, "C:", &.drive) assert_paths("C:foo", nil, "C:", &.drive) assert_paths("/foo", nil, nil, &.drive) assert_paths("//foo", nil, nil, &.drive) assert_paths("//some/share", nil, "//some/share", &.drive) assert_paths("//some/share/", nil, "//some/share", &.drive) assert_paths("//some/share/foo/", nil, "//some/share", &.drive) assert_paths("///not-a/share/", nil, nil, &.drive) assert_paths("/not-a//share/", nil, nil, &.drive) assert_paths("\\\\some\\share", nil, "\\\\some\\share", &.drive) assert_paths("\\\\some\\share\\", nil, "\\\\some\\share", &.drive) assert_paths("\\\\some\\share\\foo", nil, "\\\\some\\share", &.drive) assert_paths("\\\\\\not-a\\share", nil, nil, &.drive) assert_paths("\\\\not-a\\\\share", nil, nil, &.drive) assert_paths("\\\\?\\", nil, "\\\\?", &.drive) assert_paths("\\\\.\\", nil, "\\\\.", &.drive) assert_paths("//?/", nil, "//?", &.drive) assert_paths("//./", nil, "//.", &.drive) assert_paths("//?", nil, "//?", &.drive) assert_paths("//.", nil, "//.", &.drive) assert_paths("\\\\some$\\share\\", nil, "\\\\some$\\share", &.drive) assert_paths("\\\\%10%20\\share\\", nil, "\\\\%10%20\\share", &.drive) assert_paths("\\\\_.-~!$;=&'()*+,aB1\\ !-.@^_`{}~#$%&'()aB1\\", nil, "\\\\_.-~!$;=&'()*+,aB1\\ !-.@^_`{}~#$%&'()aB1", &.drive) assert_paths("\\\\127.0.0.1\\share\\", nil, "\\\\127.0.0.1\\share", &.drive) end describe "#root" do assert_paths("C:\\foo", nil, "\\", &.root) assert_paths("C:/foo", nil, "/", &.root) assert_paths("C:foo", nil, nil, &.root) assert_paths("/foo", "/", &.root) assert_paths("//foo", "/", &.root) assert_paths("\\foo", nil, "\\", &.root) assert_paths("\\\\foo", nil, "\\", &.root) assert_paths("//some/share", "/", nil, &.root) assert_paths("\\\\some\\share", nil, &.root) assert_paths("//some/share/", "/", "/", &.root) assert_paths("\\\\some\\share\\", nil, "\\", &.root) assert_paths("\\\\?\\", nil, "\\", &.root) assert_paths("\\\\.\\", nil, "\\", &.root) assert_paths("//?/", "/", "/", &.root) assert_paths("//./", "/", "/", &.root) assert_paths("//?", "/", nil, &.root) assert_paths("//.", "/", nil, &.root) end describe "#anchor" do assert_paths("C:\\foo", nil, "C:\\", &.anchor) assert_paths("C:/foo", nil, "C:/", &.anchor) assert_paths("C:foo", nil, "C:", &.anchor) assert_paths("/foo", "/", &.anchor) assert_paths("\\foo", nil, "\\", &.anchor) assert_paths("//some/share", "/", "//some/share", &.anchor) assert_paths("//some/share/", "/", "//some/share/", &.anchor) assert_paths("\\\\some\\share", nil, "\\\\some\\share", &.anchor) assert_paths("\\\\some\\share\\", nil, "\\\\some\\share\\", &.anchor) assert_paths("\\\\?\\", nil, "\\\\?\\", &.anchor) assert_paths("\\\\.\\", nil, "\\\\.\\", &.anchor) assert_paths("//?/", "/", "//?/", &.anchor) assert_paths("//./", "/", "//./", &.anchor) assert_paths("//?", "/", "//?", &.anchor) assert_paths("//.", "/", "//.", &.anchor) end describe "#normalize" do describe "path with forward slash" do describe "already clean" do it_normalizes_path("", ".", ".") it_normalizes_path("abc") it_normalizes_path("abc/def", windows: "abc\\def") it_normalizes_path("a/b/c", windows: "a\\b\\c") it_normalizes_path(".") it_normalizes_path("..") it_normalizes_path("../..", windows: "..\\..") it_normalizes_path("../../abc", windows: "..\\..\\abc") it_normalizes_path("/abc", windows: "\\abc") it_normalizes_path("/", windows: "\\") end describe "removes trailing slash" do it_normalizes_path("abc/", "abc", "abc") it_normalizes_path("abc/def/", "abc/def", "abc\\def") it_normalizes_path("a/b/c/", "a/b/c", "a\\b\\c") it_normalizes_path("./", ".", ".") it_normalizes_path("../", "..", "..") it_normalizes_path("../../", "../..", "..\\..") it_normalizes_path("/abc/", "/abc", "\\abc") end describe "removes double slash" do it_normalizes_path("abc//def//ghi", "abc/def/ghi", "abc\\def\\ghi") it_normalizes_path("//abc", "/abc", "\\abc") it_normalizes_path("///abc", "/abc", "\\abc") it_normalizes_path("//abc//", "/abc", "\\abc") it_normalizes_path("abc//", "abc", "abc") end describe "removes ." do it_normalizes_path("abc/./def", "abc/def", "abc\\def") it_normalizes_path("/./abc/def", "/abc/def", "\\abc\\def") it_normalizes_path("abc/.", "abc", "abc") end describe "removes .." do it_normalizes_path("abc/def/ghi/../jkl", "abc/def/jkl", "abc\\def\\jkl") it_normalizes_path("abc/def/../ghi/../jkl", "abc/jkl", "abc\\jkl") it_normalizes_path("abc/def/..", "abc", "abc") it_normalizes_path("abc/def/../..", ".", ".") it_normalizes_path("/abc/def/../..", "/", "\\") it_normalizes_path("abc/def/../../..", "..", "..") it_normalizes_path("/abc/def/../../..", "/", "\\") it_normalizes_path("abc/def/../../../ghi/jkl/../../../mno", "../../mno", "..\\..\\mno") end describe "combinations" do it_normalizes_path("abc/./../def", "def", "def") it_normalizes_path("abc//./../def", "def", "def") it_normalizes_path("abc/../../././../def", "../../def", "..\\..\\def") end end describe "paths with backslash" do describe "already clean" do it_normalizes_path("abc\\def") it_normalizes_path("a\\b\\c") it_normalizes_path("..\\..") it_normalizes_path("..\\..\\abc") it_normalizes_path("\\abc") it_normalizes_path("\\") end describe "removes trailing slash" do it_normalizes_path("abc\\", windows: "abc") it_normalizes_path("abc\\def\\", windows: "abc\\def") it_normalizes_path("a\\b\\c\\", windows: "a\\b\\c") it_normalizes_path(".\\", windows: ".") it_normalizes_path("..\\", windows: "..") it_normalizes_path("..\\..\\", windows: "..\\..") it_normalizes_path("\\abc\\", windows: "\\abc") end describe "removes double slash" do it_normalizes_path("abc\\\\def\\\\ghi", windows: "abc\\def\\ghi") it_normalizes_path("\\\\abc", windows: "\\abc") it_normalizes_path("\\\\\\abc", windows: "\\abc") it_normalizes_path("\\\\abc\\\\", windows: "\\abc") it_normalizes_path("abc\\\\", windows: "abc") end describe "removes ." do it_normalizes_path("abc\\.\\def", windows: "abc\\def") it_normalizes_path("\\.\\abc\\def", windows: "\\abc\\def") it_normalizes_path("abc\\.", windows: "abc") end describe "removes .." do it_normalizes_path("abc\\def\\ghi\\..\\jkl", windows: "abc\\def\\jkl") it_normalizes_path("abc\\def\\..\\ghi\\..\\jkl", windows: "abc\\jkl") it_normalizes_path("abc\\def\\..", windows: "abc") it_normalizes_path("abc\\def\\..\\..", windows: ".") it_normalizes_path("\\abc\\def\\..\\..", windows: "\\") it_normalizes_path("abc\\def\\..\\..\\..", windows: "..") it_normalizes_path("\\abc\\def\\..\\..\\..", windows: "\\") it_normalizes_path("abc\\def\\..\\..\\..\\ghi\\jkl\\..\\..\\..\\mno", windows: "..\\..\\mno") end describe "combinations" do it_normalizes_path("abc\\.\\..\\def", windows: "def") it_normalizes_path("abc\\\\.\\..\\def", windows: "def") it_normalizes_path("abc\\..\\..\\.\\.\\..\\def", windows: "..\\..\\def") end end describe "with drive" do it_normalizes_path("C:", "C:") it_normalizes_path("C:\\", "C:\\") it_normalizes_path("C:/", "C:", "C:\\") it_normalizes_path("C:foo", "C:foo") it_normalizes_path("C:\\foo", "C:\\foo") it_normalizes_path("C:/foo", "C:/foo", "C:\\foo") end describe "windows local device paths" do it_normalizes_path("\\\\.\\C:\\..\\D:\\foo\\.\\bar", windows: "\\\\.\\D:\\foo\\bar") it_normalizes_path("//./c:/", "/c:", windows: "\\\\.\\c:\\") it_normalizes_path("//?/c:", "/?/c:", windows: "\\\\?\\c:") it_normalizes_path("\\/.\\c:/\\", windows: "\\\\.\\c:\\") it_normalizes_path("\\\\?\\c:\\") end end describe "#join" do it_joins_path("", "", "/", "\\") it_joins_path("/", "", "/") it_joins_path("", "/", "/") it_joins_path("foo", {"bar", ""}, "foo/bar/", "foo\\bar\\") it_joins_path("foo", {"bar", ""}, "foo/bar/", "foo\\bar\\") it_joins_path("///foo", "bar", "///foo/bar", "///foo\\bar") it_joins_path("///foo", "//bar", "///foo//bar") it_joins_path("/foo/", "/bar", "/foo/bar") it_joins_path("foo", "/", "foo/") it_joins_path("foo", {"bar", "baz"}, "foo/bar/baz", "foo\\bar\\baz") it_joins_path("foo", {"//bar//", "baz///"}, "foo//bar//baz///") it_joins_path("/foo/", {"/bar/", "/baz/"}, "/foo/bar/baz/") it_joins_path("", "a", "a") it_joins_path("/", "a", "/a") it_joins_path("", "/a", "/a") it_joins_path("foo", {"/", "bar"}, "foo/bar") it_joins_path("foo", {"/", "/", "bar"}, "foo/bar") it_joins_path("/", {"/foo", "/", "bar/", "/"}, "/foo/bar/") it_joins_path("c:/", "Program Files", "c:/Program Files") it_joins_path("c:", "Program Files", "c:/Program Files", "c:\\Program Files") it_joins_path("\\\\\\\\foo", "bar", "\\\\\\\\foo/bar", "\\\\\\\\foo\\bar") it_joins_path("\\\\\\foo", "\\\\bar", "\\\\\\foo/\\\\bar", "\\\\\\foo\\\\bar") it_joins_path("\\foo\\", "\\bar", "\\foo\\/\\bar", "\\foo\\bar") it_joins_path("foo", "\\", "foo/\\", "foo\\") it_joins_path("foo", {"\\\\bar\\\\", "baz\\\\\\"}, "foo/\\\\bar\\\\/baz\\\\\\", "foo\\\\bar\\\\baz\\\\\\") it_joins_path("\\foo\\", {"\\bar\\", "\\baz\\"}, "\\foo\\/\\bar\\/\\baz\\", "\\foo\\bar\\baz\\") it_joins_path("\\", "a", "\\/a", "\\a") it_joins_path("", "\\a", "\\a") it_joins_path("foo", {"\\", "bar"}, "foo/\\/bar", "foo\\bar") it_joins_path("foo", {"\\", "\\", "bar"}, "foo/\\/\\/bar", "foo\\bar") it_joins_path("\\", {"\\foo", "\\", "bar\\", "\\"}, "\\/\\foo/\\/bar\\/\\", "\\foo\\bar\\") it_joins_path("c:\\", "Program Files", "c:\\/Program Files", "c:\\Program Files") it_joins_path("foo", Path.windows("bar\\baz"), "foo/bar/baz", "foo\\bar\\baz") it_joins_path("foo", Path.posix("bar\\baz"), "foo/bar\\baz", "foo\\bar\uF05Cbaz") it_joins_path("foo", Path.posix("bar/baz"), "foo/bar/baz", "foo\\bar/baz") end describe "#expand" do describe "converts a pathname to an absolute pathname" do it_expands_path("", BASE_POSIX, BASE_WINDOWS) it_expands_path("a", {BASE_POSIX, "a"}, {BASE_WINDOWS, "a"}) it_expands_path("a", {BASE_POSIX, "a"}, {BASE_WINDOWS, "a"}, base: nil) end describe "converts a pathname to an absolute pathname, Ruby-Talk:18512" do it_expands_path(".a", {BASE_POSIX, ".a"}, {BASE_WINDOWS, ".a"}) it_expands_path("..a", {BASE_POSIX, "..a"}, {BASE_WINDOWS, "..a"}) it_expands_path("a../b", {BASE_POSIX, "a../b"}, {BASE_WINDOWS, "a..\\b"}) end describe "keeps trailing dots on absolute pathname" do it_expands_path("a.", {BASE_POSIX, "a."}, {BASE_WINDOWS, "a."}) it_expands_path("a..", {BASE_POSIX, "a.."}, {BASE_WINDOWS, "a.."}) end describe "converts a pathname to an absolute pathname, using a complete path" do it_expands_path("", "/tmp", "\\tmp", base: Path.posix("/tmp")) it_expands_path("", "C:/tmp", "C:\\tmp", base: Path.windows("C:\\tmp")) it_expands_path("a", "/tmp/a", "\\tmp\\a", base: Path.posix("/tmp")) it_expands_path("a", "C:/tmp/a", "C:\\tmp\\a", base: Path.windows("C:\\tmp")) it_expands_path("../a", "/tmp/a", "\\tmp\\a", base: Path.posix("/tmp/xxx")) it_expands_path("../a", "C:/tmp/a", "C:\\tmp\\a", base: Path.windows("C:\\tmp\\xxx")) it_expands_path("../a", "/tmp/a", "\\tmp\\a", base: Path.posix("/tmp/xxx")) it_expands_path("../a", "C:/tmp/a", "C:\\tmp\\a", base: Path.windows("C:\\tmp\\xxx")) it_expands_path(".", "/", "\\", base: Path.posix("/")) pending { it_expands_path(".", "C:/", "C:\\", base: Path.windows("C:\\")) } end describe "expands a path with multi-byte characters" do it_expands_path("Ångström", "#{BASE_POSIX}/Ångström", "#{BASE_WINDOWS}\\Ångström") end describe "expands /./dir to /dir" do it_expands_path("/./dir", "/dir", "\\dir", base: "/") end describe "replaces multiple / with a single /" do it_expands_path("//some/path", "/some/path", "\\\\some\\path#{BASE_WINDOWS}\\") # Windows path is UNC share it_expands_path("////some/path", "/some/path", "\\some\\path") it_expands_path("/some////path", "/some/path", "\\some\\path") end describe "expand path with .." do it_expands_path("../../bin", "/bin", "\\bin", base: "/tmp/x") it_expands_path("../../bin", "/bin", "\\bin", base: "/tmp") it_expands_path("../../bin", "/bin", "\\bin", base: "/") it_expands_path("../bin", {Dir.current.gsub('\\', '/'), "tmp", "bin"}, {Path.windows(Dir.current).normalize.to_s, "tmp", "bin"}, base: "tmp/x", expand_base: true) it_expands_path("../bin", {Dir.current.gsub('\\', '/'), "bin"}, {Path.windows(Dir.current).normalize.to_s, "bin"}, base: "x/../tmp", expand_base: true) end describe "expand_path for common unix path gives a full path" do it_expands_path("/tmp/", "/tmp/", "\\tmp\\") it_expands_path("/tmp/../../../tmp", "/tmp", "\\tmp") it_expands_path("", BASE_POSIX, BASE_WINDOWS) it_expands_path("./////", "#{BASE_POSIX}/", "#{BASE_WINDOWS}\\") it_expands_path(".", BASE_POSIX, BASE_WINDOWS) it_expands_path(BASE_POSIX, BASE_POSIX, BASE_POSIX.gsub('/', '\\')) end describe "with drive" do it_expands_path("foo", "D:/foo", "D:foo", base: "D:") it_expands_path("/foo", "/foo", "D:\\foo", base: "D:") it_expands_path("\\foo", "D:/\\foo", "D:\\foo", base: "D:") it_expands_path("foo", "D:\\/foo", "D\uF03A\uF05C\\foo", base: Path.posix("D:\\")) it_expands_path("foo", "D:/foo", "D:\\foo", base: Path.windows("D:\\")) it_expands_path("foo", "D:/foo", "D:\\foo", base: "D:/") it_expands_path("/foo", "/foo", "D:\\foo", base: "D:\\") it_expands_path("\\foo", "D:\\/\\foo", "\\foo", base: Path.posix("D:\\")) it_expands_path("\\foo", "D:/\\foo", "D:\\foo", base: Path.windows("D:\\")) it_expands_path("/foo", "/foo", "D:\\foo", base: "D:/") it_expands_path("\\foo", "D:/\\foo", "D:\\foo", base: "D:/") it_expands_path("C:", "D:/C:", "C:", base: "D:") it_expands_path("C:", "D:/C:", "C:\\", base: "D:/") it_expands_path("C:", "D:\\/C:", "C:D\uF03A\uF05C\\", base: Path.posix("D:\\")) it_expands_path("C:", "D:/C:", "C:\\", base: Path.windows("D:\\")) it_expands_path("C:/", "D:/C:/", "C:\\", base: "D:") it_expands_path("C:/", "D:/C:/", "C:\\", base: "D:/") it_expands_path("C:/", "D:\\/C:/", "C:\\", base: Path.posix("D:\\")) it_expands_path("C:/", "D:/C:/", "C:\\", base: Path.windows("D:\\")) it_expands_path("C:\\", "D:/C:\\", "C:\\", base: "D:") it_expands_path("C:\\", "D:/C:\\", "C:\\", base: "D:/") it_expands_path("C:\\", "D:\\/C:\\", "C:\\", base: Path.posix("D:\\")) it_expands_path("C:\\", "D:/C:\\", "C:\\", base: Path.windows("D:\\")) it_expands_path("C:foo", "D:/C:foo", "C:foo", base: "D:") it_expands_path("C:/foo", "D:/C:/foo", "C:\\foo", base: "D:") it_expands_path("C:\\foo", "D:/C:\\foo", "C:\\foo", base: "D:") it_expands_path("C:foo", "D:\\/C:foo", "C:D\uF03A\uF05C\\foo", base: Path.posix("D:\\")) it_expands_path("C:foo", "D:/C:foo", "C:\\foo", base: Path.windows("D:\\")) it_expands_path("C:foo", "D:/C:foo", "C:\\foo", base: "D:/") it_expands_path("C:/foo", "D:\\/C:/foo", "C:\\foo", base: Path.posix("D:\\")) it_expands_path("C:/foo", "D:/C:/foo", "C:\\foo", base: Path.windows("D:\\")) it_expands_path("C:\\foo", "D:\\/C:\\foo", "C:\\foo", base: Path.posix("D:\\")) it_expands_path("C:\\foo", "D:/C:\\foo", "C:\\foo", base: Path.windows("D:\\")) it_expands_path("C:/foo", "D:/C:/foo", "C:\\foo", base: "D:/") it_expands_path("C:\\foo", "D:/C:\\foo", "C:\\foo", base: "D:/") end describe "UNC path" do it_expands_path("baz", "/foo/bar/baz", "\\\\foo\\bar\\baz", base: Path.windows("\\\\foo\\bar\\")) it_expands_path("baz", "/foo$/bar/baz", "\\\\foo$\\bar\\baz", base: Path.windows("\\\\foo$\\bar\\")) end it "doesn't expand ~" do [Path["~"], Path["~", "foo"]].each do |path| path.expand(base: "", expand_base: false).should eq path end end describe "checks all possible types for expand(home:)" do home_posix2 = Path.posix(BASE_POSIX).join("foo").to_s home_windows2 = Path.windows(BASE_WINDOWS).join("foo").to_s home = Path[""].windows? ? home_windows2 : home_posix2 it_expands_path("~/a", {BASE_POSIX, "~/a"}, {BASE_WINDOWS, "~\\a"}, home: false) it_expands_path("~/a", {home_posix2, "a"}, {home_windows2, "a"}, home: home) it_expands_path("~/a", {home_posix2, "a"}, {home_windows2, "a"}, home: Path[home]) end describe "converts a pathname to an absolute pathname, using ~ (home) as base" do it_expands_path("~/", {HOME_POSIX, ""}, {HOME_WINDOWS, ""}, home: true) it_expands_path("~/..badfilename", {HOME_POSIX, "..badfilename"}, {HOME_WINDOWS, "..badfilename"}, home: true) it_expands_path("..", "/default", "\\default", home: true) it_expands_path("~/a", {HOME_POSIX, "a"}, {HOME_WINDOWS, "a"}, base: "~/b", home: true) it_expands_path("~", HOME_POSIX, HOME_WINDOWS, home: true) it_expands_path("~", HOME_POSIX, HOME_WINDOWS, base: "/tmp/gumby/ddd", home: true) it_expands_path("~/a", {HOME_POSIX, "a"}, {HOME_WINDOWS, "a"}, base: "/tmp/gumby/ddd", home: true) end describe "converts a pathname to an absolute pathname, using ~ (home) as base (trailing /)" do it_expands_path("~/", {HOME_POSIX, ""}, {HOME_WINDOWS, ""}, home: true) it_expands_path("~/..badfilename", {"#{HOME_POSIX}/", "..badfilename"}, {"#{HOME_WINDOWS}\\", "..badfilename"}, base: "", home: true) it_expands_path("~/..", "/home", "C:\\Users", home: true) it_expands_path("~/a", {HOME_POSIX, "a"}, {HOME_WINDOWS, "a"}, base: "~/b", home: true) it_expands_path("~", HOME_POSIX, HOME_WINDOWS, home: true) it_expands_path("~", HOME_POSIX, HOME_WINDOWS, base: "/tmp/gumby/ddd", home: true) it_expands_path("~/a", {HOME_POSIX, "a"}, {HOME_WINDOWS, "a"}, base: "/tmp/gumby/ddd", home: true) end describe "converts a pathname to an absolute pathname, using ~ (home) as base (HOME=/)" do it_expands_path("~/", "/", "\\", env_home: "/", home: true) it_expands_path("~/..badfilename", "/..badfilename", "\\..badfilename", env_home: "/", home: true) it_expands_path("..", "/default", "\\default", env_home: "/", home: true) it_expands_path("~/a", "/a", "\\a", base: "~/b", env_home: "/", home: true) it_expands_path("~", "/", "\\", env_home: "/", home: true) it_expands_path("~", "/", "\\", base: "/tmp/gumby/ddd", env_home: "/", home: true) it_expands_path("~/a", "/a", "\\a", base: "/tmp/gumby/ddd", env_home: "/", home: true) end describe "ignores name starting with ~" do it_expands_path("~foo.txt", "/current/~foo.txt", "\\current\\~foo.txt", base: "/current", env_home: "/") end describe %q(supports ~\ for Windows paths only) do it_expands_path("~\\a", {BASE_POSIX, "~\\a"}, {HOME_WINDOWS, "a"}, home: true) end end describe "#<=>" do it "case sensitivity" do (Path.posix("foo") <=> Path.posix("FOO")).should eq 1 (Path.windows("foo") <=> Path.windows("FOO")).should eq 0 (Path.windows("foo") <=> Path.posix("FOO")).should eq 1 (Path.posix("foo") <=> Path.windows("FOO")).should eq -1 end end describe "#==" do it "simple" do Path.posix("foo").should eq Path.posix("foo") Path.windows("foo").should eq Path.windows("foo") Path.windows("foo").should_not eq Path.posix("foo") Path.posix("foo").should_not eq Path.windows("foo") end it "case sensitivity" do Path.posix("foo").should_not eq Path.posix("FOO") Path.windows("foo").should eq Path.windows("FOO") Path.windows("foo").should_not eq Path.posix("FOO") Path.posix("foo").should_not eq Path.windows("FOO") end end describe "#ends_with_separator?" do assert_paths_raw("foo", false, &.ends_with_separator?) assert_paths_raw("foo/", true, &.ends_with_separator?) assert_paths_raw("foo\\", false, true, &.ends_with_separator?) assert_paths_raw("C:/", true, &.ends_with_separator?) assert_paths_raw("foo/bar", false, &.ends_with_separator?) assert_paths_raw("foo/.", false, &.ends_with_separator?) end describe "#to_windows" do assert_paths_raw("C:\\foo\\bar", Path.windows("C\uF03A\uF05Cfoo\uF05Cbar"), Path.windows("C:\\foo\\bar"), label: "default: mappings=true", &.to_windows) assert_paths_raw("foo/bar", Path.windows("foo/bar"), &.to_windows(mappings: true)) assert_paths_raw("C:\\foo\\bar", Path.windows("C\uF03A\uF05Cfoo\uF05Cbar"), Path.windows("C:\\foo\\bar"), &.to_windows(mappings: true)) assert_paths_raw(%("*/:<>?\\| ), Path.windows("\uF022\uF02A/\uF03A\uF03C\uF03E\uF03F\uF05C\uF07C\uF020"), Path.windows(%("*/:<>?\\| )), &.to_windows(mappings: true)) assert_paths_raw("foo/bar", Path.windows("foo/bar"), &.to_windows(mappings: false)) assert_paths_raw("C:\\foo\\bar", Path.windows("C:\\foo\\bar"), &.to_windows(mappings: false)) assert_paths_raw(%("*/:<>?\\| ), Path.windows(%("*/:<>?\\| )), &.to_windows(mappings: false)) end describe "#to_posix" do assert_paths_raw("C\uF03A\uF05Cfoo\uF05Cbar", Path.posix("C\uF03A\uF05Cfoo\uF05Cbar"), Path.posix("C:\\foo\\bar"), label: "default: mappings=true", &.to_posix) assert_paths_raw("foo/bar", Path.posix("foo/bar"), &.to_posix(mappings: true)) assert_paths_raw("C:\\foo\\bar", Path.posix("C:\\foo\\bar"), Path.posix("C:/foo/bar"), &.to_posix(mappings: true)) assert_paths_raw("C\uF03A\uF05Cfoo\uF05Cbar", Path.posix("C\uF03A\uF05Cfoo\uF05Cbar"), Path.posix("C:\\foo\\bar"), &.to_posix(mappings: true)) assert_paths_raw("\uF022\uF02A/\uF03A\uF03C\uF03E\uF03F\uF05C\uF07C\uF020", Path.posix("\uF022\uF02A/\uF03A\uF03C\uF03E\uF03F\uF05C\uF07C\uF020"), Path.posix(%("*/:<>?\\| )), &.to_posix(mappings: true)) assert_paths_raw("foo/bar", Path.posix("foo/bar"), &.to_posix(mappings: false)) assert_paths_raw("C:\\foo\\bar", Path.posix("C:\\foo\\bar"), Path.posix("C:/foo/bar"), &.to_posix(mappings: false)) assert_paths_raw("C\uF03A\uF05Cfoo\uF05Cbar", Path.posix("C\uF03A\uF05Cfoo\uF05Cbar"), &.to_posix(mappings: false)) assert_paths_raw("\uF022\uF02A/\uF03A\uF03C\uF03E\uF03F\uF05C\uF07C\uF020", Path.posix("\uF022\uF02A/\uF03A\uF03C\uF03E\uF03F\uF05C\uF07C\uF020"), &.to_posix(mappings: false)) end describe "#relative_to?" do it_relativizes("a/b", "a/b/c", "c") it_relativizes("a/b", "a/b", ".") it_relativizes("a/b/.", "a/b", ".") it_relativizes("a/b", "a/b/.", ".") it_relativizes("./a/b", "a/b", ".") it_relativizes("a/b", "./a/b", ".") it_relativizes("ab/cd", "ab/cde", "../cde", "..\\cde") it_relativizes("ab/cd", "ab/c", "../c", "..\\c") it_relativizes("a/b", "a/b/c/d", "c/d", "c\\d") it_relativizes("a/b", "a/b/../c", "../c", "..\\c") it_relativizes("a/b/../c", "a/b", "../b", "..\\b") it_relativizes("a/b/c", "a/c/d", "../../c/d", "..\\..\\c\\d") it_relativizes("a/b", "c/d", "../../c/d", "..\\..\\c\\d") it_relativizes("a/b/c/d", "a/b", "../..", "..\\..") it_relativizes("a/b/c/d", "a/b/", "../..", "..\\..") it_relativizes("a/b/c/d/", "a/b", "../..", "..\\..") it_relativizes("a/b/c/d/", "a/b/", "../..", "..\\..") it_relativizes("../../a/b", "../../a/b/c/d", "c/d", "c\\d") it_relativizes("/a/b", "/a/b", ".") it_relativizes("/a/b/.", "/a/b", ".") it_relativizes("/a/b", "/a/b/.", ".") it_relativizes("/ab/cd", "/ab/cde", "../cde", "..\\cde") it_relativizes("/ab/cd", "/ab/c", "../c", "..\\c") it_relativizes("/a/b", "/a/b/c/d", "c/d", "c\\d") it_relativizes("/a/b", "/a/b/../c", "../c", "..\\c") it_relativizes("/a/b/../c", "/a/b", "../b", "..\\b") it_relativizes("/a/b/c", "/a/c/d", "../../c/d", "..\\..\\c\\d") it_relativizes("/a/b", "/c/d", "../../c/d", "..\\..\\c\\d") it_relativizes("/a/b/c/d", "/a/b", "../..", "..\\..") it_relativizes("/a/b/c/d", "/a/b/", "../..", "..\\..") it_relativizes("/a/b/c/d/", "/a/b", "../..", "..\\..") it_relativizes("/a/b/c/d/", "/a/b/", "../..", "..\\..") it_relativizes("/../../a/b", "/../../a/b/c/d", "c/d", "c\\d") it_relativizes("/", "/a/c", "a/c", "a\\c") it_relativizes("/", "/", ".") it_relativizes(".", "a/b", "a/b", "a\\b") it_relativizes(".", "..", "..") # can't do purely lexically it_relativizes("..", ".", nil) it_relativizes("..", "a", nil) it_relativizes("../..", "..", nil) it_relativizes("a", "/a", nil) describe "special windows paths" do it_relativizes("/a", "a", nil) it_relativizes("C:a\\b\\c", "C:a/b/d", "../C:a/b/d", "..\\d") it_relativizes("C:a\\b\\c", "c:a/b/d", "../c:a/b/d", "..\\d") it_relativizes("C:\\", "D:\\", "../D:\\", nil) it_relativizes("C:", "D:", "../D:", nil) it_relativizes("C:\\Projects", "c:\\projects\\src", "../c:\\projects\\src", "src") it_relativizes("C:\\Projects", "c:\\projects", "../c:\\projects", ".") it_relativizes("C:\\Projects\\a\\..", "c:\\projects", "../c:\\projects", ".") it_relativizes("C:\\foo", "C:/bar", "../C:/bar", "..\\bar") end end describe "#relative_to" do it "relativizable paths" do Path.posix("a/b/c").relative_to("a/b").should eq Path.posix("c") Path.windows("a\\b\\c").relative_to("a\\b").should eq Path.windows("c") end it "mixed input paths" do Path.posix("a/b/c").relative_to(Path.windows("a\\b")).should eq Path.posix("c") Path.windows("a\\b\\c").relative_to(Path.posix("a/b")).should eq Path.windows("c") end it "paths that can't be relativized" do path = Path.posix(".") path.relative_to(Path.posix("/cwd")).should eq path path = Path.windows(".") path.relative_to(Path.windows("/cwd")).should eq path path = Path.windows(".") path.relative_to(Path.windows("C:/cwd")).should eq path path = Path.windows(".") path.relative_to(Path.windows("C:cwd")).should eq path end end describe "#stem" do assert_paths_raw("foo.txt", "foo", &.stem) assert_paths_raw("foo.txt.txt", "foo.txt", &.stem) assert_paths_raw(".txt", ".txt", &.stem) assert_paths_raw(".txt.txt", ".txt", &.stem) assert_paths_raw("foo.", "foo.", &.stem) assert_paths_raw("foo.txt.", "foo.txt.", &.stem) assert_paths_raw("foo..txt", "foo.", &.stem) assert_paths_raw("bar/foo.txt", "foo", &.stem) assert_paths_raw("bar/foo.txt.txt", "foo.txt", &.stem) assert_paths_raw("bar/.txt", ".txt", &.stem) assert_paths_raw("bar/.txt.txt", ".txt", &.stem) assert_paths_raw("bar/foo.", "foo.", &.stem) assert_paths_raw("bar/foo.txt.", "foo.txt.", &.stem) assert_paths_raw("bar/foo..txt", "foo.", &.stem) assert_paths_raw("bar\\foo.txt", "bar\\foo", "foo", &.stem) assert_paths_raw("bar\\foo.txt.txt", "bar\\foo.txt", "foo.txt", &.stem) assert_paths_raw("bar\\.txt", "bar\\", ".txt", &.stem) assert_paths_raw("bar\\.txt.txt", "bar\\.txt", ".txt", &.stem) assert_paths_raw("bar\\foo.", "bar\\foo.", "foo.", &.stem) assert_paths_raw("bar\\foo.txt.", "bar\\foo.txt.", "foo.txt.", &.stem) assert_paths_raw("bar\\foo..txt", "bar\\foo.", "foo.", &.stem) assert_paths_raw("foo.txt/", "foo", &.stem) assert_paths_raw("foo.txt.txt/", "foo.txt", &.stem) assert_paths_raw(".txt/", ".txt", &.stem) assert_paths_raw(".txt.txt/", ".txt", &.stem) assert_paths_raw("foo./", "foo.", &.stem) assert_paths_raw("foo.txt./", "foo.txt.", &.stem) assert_paths_raw("foo..txt/", "foo.", &.stem) end pending_wasm32 describe: ".home" do it "uses home from environment variable if set" do with_env({HOME_ENV_KEY => "foo/bar"}) do Path.home.should eq(Path.new("foo/bar")) end end # TODO: check that the cases below return the home of the current user (via #7829) it "doesn't return empty string if environment variable is empty" do with_env({HOME_ENV_KEY => ""}) do Path.home.should_not eq(Path.new("")) end end it "doesn't raise if environment variable is missing" do with_env({HOME_ENV_KEY => nil}) do Path.home.should be_a(Path) end end end end