-- SPDX-FileCopyrightText: Copyright 2022-present Greg Hurrell and contributors.
-- SPDX-License-Identifier: BSD-2-Clause

local Path = require('wincent.commandt.private.path').Path

describe('Path', function()
  describe('Path.new()', function()
    it('produces an instance that acts like a string', function()
      local path = Path.new('/etc/passwd')
      expect(tostring(path)).to_equal('/etc/passwd')
    end)
  end)

  describe('Path.join()', function()
    it('creates a path from an empty list', function()
      expect(Path.join({})).to_equal(Path.new(''))
    end)

    it('creates a path from a list of one', function()
      expect(Path.join({ '' })).to_equal(Path.new(''))
      expect(Path.join({ '/' })).to_equal(Path.new('/'))
      expect(Path.join({ '.' })).to_equal(Path.new('.'))
      expect(Path.join({ 'foo' })).to_equal(Path.new('foo'))
    end)

    it('creates a path from a list of multiple components', function()
      expect(Path.join({ '/', 'foo' })).to_equal(Path.new('/foo'))
      expect(Path.join({ 'foo', 'bar' })).to_equal(Path.new('foo/bar'))
    end)
  end)

  describe('Path.pwd()', function()
    it('returns the current working directory', function()
      expect(Path.pwd()).to_equal(Path.new(os.getenv('PWD')))
    end)
  end)

  describe('Path with `+` operator', function()
    it('produces a combined path', function()
      expect(Path.new('') + Path.new('')).to_equal(Path.new(''))
      expect(Path.new('/') + Path.new('foo')).to_equal(Path.new('/foo'))
      expect(Path.new('/foo') + Path.new('')).to_equal(Path.new('/foo'))
      expect(Path.new('') + Path.new('foo')).to_equal(Path.new('foo'))
      expect(Path.new('/foo/bar') + Path.new('baz')).to_equal(Path.new('/foo/bar/baz'))
    end)
  end)

  describe('Path with `==` operator', function()
    it('is true when the paths have the same contents', function()
      expect(Path.new('')).to_equal(Path.new(''))
      expect(Path.new('/')).to_equal(Path.new('/'))
      expect(Path.new('foo')).to_equal(Path.new('foo'))
    end)

    it('is false when the paths do not have the same contents', function()
      expect(Path.new('')).not_to_equal(Path.new('bar'))
      expect(Path.new('foo')).not_to_equal(Path.new('bar'))
      expect(Path.new('/foo')).not_to_equal(Path.new('bar'))
    end)
  end)

  describe('Path:components()', function()
    it('returns a list of components', function()
      expect(Path.new('.'):components()).to_equal({ '.' })
      expect(Path.new('/'):components()).to_equal({ '/' })
      expect(Path.new('/foo/bar'):components()).to_equal({ '/', 'foo', 'bar' })
      expect(Path.new('/foo/bar/'):components()).to_equal({ '/', 'foo', 'bar' })
      expect(Path.new('foo/bar'):components()).to_equal({ 'foo', 'bar' })
      expect(Path.new('foo//bar'):components()).to_equal({ 'foo', 'bar' })
      expect(Path.new('foo///bar'):components()).to_equal({ 'foo', 'bar' })
      expect(Path.new('./foo'):components()).to_equal({ '.', 'foo' })
      expect(Path.new('foo'):components()).to_equal({ 'foo' })
    end)
  end)

  describe('Path:is_absolute()', function()
    it('returns true for absolute paths', function()
      expect(Path.new('/'):is_absolute()).to_be(true)
      expect(Path.new('/usr'):is_absolute()).to_be(true)
      expect(Path.new('/etc/passwd'):is_absolute()).to_be(true)
    end)

    it('returns false for non-absolute paths', function()
      expect(Path.new(''):is_absolute()).to_be(false)
      expect(Path.new('.'):is_absolute()).to_be(false)
      expect(Path.new('./'):is_absolute()).to_be(false)
      expect(Path.new('..'):is_absolute()).to_be(false)
      expect(Path.new('../'):is_absolute()).to_be(false)
      expect(Path.new('foo'):is_absolute()).to_be(false)
      expect(Path.new('foo/'):is_absolute()).to_be(false)
      expect(Path.new('foo/bar'):is_absolute()).to_be(false)
      expect(Path.new('foo/bar/'):is_absolute()).to_be(false)
    end)
  end)

  describe('Path:is_relative()', function()
    it('returns true for relative paths', function()
      expect(Path.new(''):is_relative()).to_be(true)
      expect(Path.new('.'):is_relative()).to_be(true)
      expect(Path.new('./'):is_relative()).to_be(true)
      expect(Path.new('..'):is_relative()).to_be(true)
      expect(Path.new('../'):is_relative()).to_be(true)
      expect(Path.new('foo'):is_relative()).to_be(true)
      expect(Path.new('foo/'):is_relative()).to_be(true)
      expect(Path.new('foo/bar'):is_relative()).to_be(true)
      expect(Path.new('foo/bar/'):is_relative()).to_be(true)
    end)

    it('returns false for non-relative paths', function()
      expect(Path.new('/'):is_relative()).to_be(false)
      expect(Path.new('/usr'):is_relative()).to_be(false)
      expect(Path.new('/etc/passwd'):is_relative()).to_be(false)
    end)
  end)

  describe('Path:normalize()', function()
    it('removes redundant "." and ".."', function()
      expect(Path.new(''):normalize()).to_equal('.')
      expect(Path.new('.'):normalize()).to_equal('.')
      expect(Path.new('./foo'):normalize()).to_equal('foo')
      expect(Path.new('foo/.'):normalize()).to_equal('foo')
      expect(Path.new('foo/./bar'):normalize()).to_equal('foo/bar')
      expect(Path.new('foo/../bar'):normalize()).to_equal('bar')
      expect(Path.new('foo/..'):normalize()).to_equal('.')
      expect(Path.new('../foo'):normalize()).to_equal('../foo')
      expect(Path.new('../../foo'):normalize()).to_equal('../../foo')
      expect(Path.new('../../../foo'):normalize()).to_equal('../../../foo')
      expect(Path.new('a/b/c/../../foo'):normalize()).to_equal('a/foo')
    end)
  end)
end)
