local _ = require("pathlib")

describe("Resolve paths", function()
  local Posix = require("pathlib.posix")
  local Windows = require("pathlib.windows")
  local utils = require("pathlib.utils")

  local abs_posix = Posix("/etc")
  local abs_win = Windows("C:/Users")
  local rel_posix = Posix("./folder")
  local rel_windows = Windows("./folder")

  describe("Resolve relative Posix", function()
    it("no ../", function()
      assert.are_equal(Posix("folder/passwd"), rel_posix / "passwd")
      assert.are_equal("folder/passwd", tostring(rel_posix / "passwd"))
    end)
    it("one ../", function()
      assert.are_equal(Posix("var/lib"), rel_posix / "../var/lib")
      assert.are_equal(Posix("var/lib"), rel_posix / ".." / "var/lib")
      assert.are_equal(Posix("var/lib"), rel_posix.new(rel_posix .. "/../" .. "var/lib"))
      assert.are_equal("var/lib", tostring(rel_posix / ".." / "var/lib"))
    end)
    it("too many ../", function()
      assert.are_equal(Posix("../var/lib"), rel_posix / "../../var/lib")
      assert.are_equal(Posix("../var/lib"), rel_posix / ".." / ".." / "var/lib")
      assert.are_equal(Posix("../var/lib"), rel_posix.new(rel_posix .. "/../../" .. "var/lib"))
      assert.are_equal("../var/lib", tostring(rel_posix / "../.." / "var/lib"))
    end)
    it("overflow ../", function()
      assert.are_equal(Posix("../../var/lib"), rel_posix / "../../../var/lib")
      assert.are_equal(Posix("../../var/lib"), rel_posix / ".." / ".." / ".." / "var/lib")
      assert.are_equal(Posix("../../var/lib"), rel_posix.new(rel_posix .. "/../../../" .. "var/lib"))
      assert.are_equal("../../var/lib", tostring(rel_posix / "../../.." / "var/lib"))
    end)
  end)

  describe("Resolve multiple ../", function()
    it("", function()
      assert.are_equal(Posix("lib"), rel_posix / ".." / "var" / ".." / "lib")
      assert.are_equal(Posix("lib"), rel_posix / "../var/../lib")
    end)
  end)

  describe("Resolve relative Windows", function()
    it("no ../", function()
      assert.are_equal(Windows("folder/passwd"), rel_windows / "passwd")
      assert.are_equal([[folder\passwd]], tostring(rel_windows / "passwd"))
    end)
    it("one ../", function()
      assert.are_equal(Windows("var/lib"), rel_windows / "../var/lib")
      assert.are_equal(Windows("var/lib"), rel_windows / ".." / "var/lib")
      assert.are_equal(Windows("var/lib"), rel_windows.new(rel_windows .. "/../" .. "var/lib"))
      assert.are_equal([[var\lib]], tostring(rel_windows / ".." / "var/lib"))
    end)
    it("too many ../", function()
      assert.are_equal(Windows("../var/lib"), rel_windows / "../../var/lib")
      assert.are_equal(Windows("../var/lib"), rel_windows / ".." / ".." / "var/lib")
      assert.are_equal(Windows("../var/lib"), rel_windows.new(rel_windows .. "/../../" .. "var/lib"))
      assert.are_equal([[..\var\lib]], tostring(rel_windows / "../.." / "var/lib"))
    end)
    it("overflow ../", function()
      assert.are_equal(Windows("../../var/lib"), rel_windows / "../../../var/lib")
      assert.are_equal(Windows("../../var/lib"), rel_windows / ".." / ".." / ".." / "var/lib")
      assert.are_equal(Windows("../../var/lib"), rel_windows.new(rel_windows .. "/../../../" .. "var/lib"))
      assert.are_equal([[..\..\var\lib]], tostring(rel_windows / [[../../..]] / [[var/lib]]))
    end)
  end)

  describe("Resolve absolute Posix", function()
    it("no ../", function()
      assert.are_equal(Posix("/etc/passwd"), abs_posix / "passwd")
      assert.are_equal("/etc/passwd", tostring(abs_posix / "passwd"))
    end)
    it("one ../", function()
      assert.are_equal(Posix("/var/lib"), abs_posix / "../var/lib")
      assert.are_equal(Posix("/var/lib"), abs_posix / ".." / "var/lib")
      assert.are_equal(Posix("/var/lib"), abs_posix.new(abs_posix .. "/../" .. "var/lib"))
      assert.are_equal("/var/lib", tostring(abs_posix / ".." / "var/lib"))
    end)
    it("too many ../", function()
      assert.has_error(function()
        return abs_posix / "../../var/lib"
      end)
      assert.has_error(function()
        return abs_posix / ".." / ".." / "var/lib"
      end)
      assert.has_error(function()
        return abs_posix.new(abs_posix .. "/../../" .. "var/lib")
      end)
      assert.has_error(function()
        return tostring(abs_posix / "../.." / "var/lib")
      end)
    end)
    it("overflow ../", function()
      assert.has_error(function()
        return abs_posix / "../../../var/lib"
      end)
      assert.has_error(function()
        return abs_posix / ".." / ".." / ".." / "var/lib"
      end)
      assert.has_error(function()
        return abs_posix.new(abs_posix .. "/../../../" .. "var/lib")
      end)
      assert.has_error(function()
        return tostring(abs_posix / "../../.." / "var/lib")
      end)

      -- allow_abs2rel
      assert.has_no_error(function()
        return abs_posix:child_unpack("../../var/lib"):resolve(true)
      end)
      assert.are_equal(Posix("../var/lib"), abs_posix:descendant("..", "..", "..", "var", "lib"):resolve(true))
    end)
  end)

  describe("Resolve absolute Windows", function()
    it("no ../", function()
      assert.are_equal(Windows("C:/Users/passwd"), abs_win / "passwd")
      assert.are_equal([[C:\Users\passwd]], tostring(abs_win / "passwd"))
    end)
    it("one ../", function()
      assert.are_equal(Windows([[C:\var\lib]]), abs_win / "../var/lib")
      assert.are_equal(Windows([[C:\var\lib]]), abs_win / ".." / "var/lib")
      assert.are_equal(Windows([[C:\var\lib]]), abs_win.new(abs_win .. "/../" .. "var/lib"))
      assert.are_equal([[C:\var\lib]], tostring(abs_win / ".." / "var/lib"))
    end)
    it("too many ../", function()
      assert.has_error(function()
        return abs_win / "../../var/lib"
      end)
      assert.has_error(function()
        return abs_win / ".." / ".." / "var/lib"
      end)
      assert.has_error(function()
        return abs_win.new(abs_win .. "/../../" .. "var/lib")
      end)
      assert.has_error(function()
        return tostring(abs_win / "../.." / "var/lib")
      end)

      -- allow_abs2rel
      assert.has_no_error(function()
        return abs_win:child_unpack([[..\..\var\lib]]):resolve(true)
      end)
      assert.are_equal(Windows([[C:../var/lib]]), abs_win:descendant("..", "..", "..", "var", "lib"):resolve(true))
    end)
    it("overflow ../", function()
      assert.has_error(function()
        return abs_win / "../../../var/lib"
      end)
      assert.has_error(function()
        return abs_win / ".." / ".." / ".." / "var/lib"
      end)
      assert.has_error(function()
        return abs_win.new(abs_win .. "/../../../" .. "var/lib")
      end)
      assert.has_error(function()
        return tostring(abs_win / "../../.." / "var/lib")
      end)
    end)
  end)

  describe("Resolve multiple ../ in between", function()
    it("posix", function()
      assert.are_equal(Posix("lib"), rel_posix / ".." / "var" / ".." / "lib")
      assert.are_equal(Posix("lib"), rel_posix / "../var/../lib")
    end)

    it("posix overflow", function()
      assert.are_equal(Posix("../lib"), rel_posix / ".." / "var" / ".." / ".." / "lib")
      assert.are_equal(Posix("../lib"), rel_posix / "../var/../../lib")
    end)

    it("windows", function()
      assert.are_equal(Windows("lib"), rel_windows / ".." / "var" / ".." / "lib")
      assert.are_equal(Windows("lib"), rel_windows / "../var/../lib")
    end)
    it("windows overflow", function()
      assert.are_equal(Windows("../lib"), rel_windows / ".." / "var" / ".." / ".." / "lib")
      assert.are_equal(Windows("../lib"), rel_windows / "../var/../../lib")
    end)
  end)
end)
