#!/usr/bin/env python
#
# Copyright 2019 The Cobalt Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Unit tests for port_symlink.py."""

import os
import shutil
import tempfile
import unittest

from starboard.tools import port_symlink
from starboard.tools import util

_TARGET_FILENAME = 'target.txt'


# Replace this function signature for other implementations of symlink
# functions.
def MakeSymLink(*args, **kwargs):
  return port_symlink.MakeSymLink(*args, **kwargs)


def IsSymLink(*args, **kwargs):
  return port_symlink.IsSymLink(*args, **kwargs)


def ReadSymLink(*args, **kwargs):
  return port_symlink.ReadSymLink(*args, **kwargs)


def Rmtree(*args, **kwargs):
  return port_symlink.Rmtree(*args, **kwargs)


def OsWalk(*args, **kwargs):
  return port_symlink.OsWalk(*args, **kwargs)


class PortSymlinkTest(unittest.TestCase):

  def setUp(self):
    super(PortSymlinkTest, self).setUp()
    self.tmp_dir = tempfile.mkdtemp(prefix='port_symlink_')
    self.target_dir = os.path.join(self.tmp_dir, 'target')
    self.inner_dir = os.path.join(self.target_dir, 'inner')
    self.link_dir = os.path.join(self.tmp_dir, 'link')
    self.target_file = os.path.join(self.target_dir, _TARGET_FILENAME)
    _MakeDirs(self.target_dir)
    _MakeDirs(self.inner_dir)
    with open(self.target_file, 'w') as fd:
      fd.write('hallo welt!')
    MakeSymLink(self.target_dir, self.link_dir)

  def tearDown(self):
    Rmtree(self.tmp_dir)
    super(PortSymlinkTest, self).tearDown()

  def testSanity(self):
    self.assertTrue(os.path.isdir(self.tmp_dir))
    self.assertTrue(os.path.isdir(self.target_dir))
    self.assertTrue(os.path.isdir(self.inner_dir))

  def testReadSymlinkNormalPath(self):
    self.assertIsNone(ReadSymLink(self.target_dir))

  def testSymlinkPath(self):
    self.assertTrue(os.path.exists(self.link_dir))
    self.assertTrue(IsSymLink(self.link_dir))
    from_dir_2 = ReadSymLink(self.link_dir)
    self.assertTrue(_IsSamePath(from_dir_2, self.target_dir))

  def testRelativeSymlinkPath(self):
    rel_link_dir = os.path.join(self.tmp_dir, 'foo', 'rel_link')
    rel_dir_path = os.path.relpath(self.target_dir, rel_link_dir)
    MakeSymLink(rel_dir_path, rel_link_dir)
    self.assertTrue(IsSymLink(rel_link_dir))
    link_value = ReadSymLink(rel_link_dir)
    self.assertIn(
        '..', link_value, msg='Expected ".." in relative path %s' % link_value)

  def testDelSymlink(self):
    link_dir2 = os.path.join(self.tmp_dir, 'link2')
    MakeSymLink(self.target_dir, link_dir2)
    self.assertTrue(IsSymLink(link_dir2))
    port_symlink.DelSymLink(link_dir2)
    self.assertFalse(os.path.exists(link_dir2))

  def testRmtreeRemovesLink(self):
    Rmtree(self.link_dir)
    self.assertFalse(os.path.exists(self.link_dir))
    self.assertTrue(os.path.exists(self.target_dir))

  def testRmtreeRemovesBrokenLink(self):
    Rmtree(self.target_dir)
    # os.path.exists() will return false for broken links (not true for reparse
    # points on Windows) since their target does not exist. Rmtree
    # implementations should still be able to remove the link.
    if not port_symlink.IsWindows():
      self.assertFalse(os.path.exists(self.link_dir))
    self.assertTrue(IsSymLink(self.link_dir))
    Rmtree(self.link_dir)
    self.assertFalse(IsSymLink(self.link_dir))

  def testRmtreeDoesNotFollowSymlinks(self):
    """Tests that Rmtree(...) will delete the symlink and not the target."""
    external_temp_dir = tempfile.mkdtemp()
    try:
      external_temp_file = os.path.join(external_temp_dir, _TARGET_FILENAME)
      with open(external_temp_file, 'w') as fd:
        fd.write('hallo!')
      link_dir = os.path.join(self.tmp_dir, 'foo', 'link_dir')
      MakeSymLink(external_temp_file, link_dir)
      Rmtree(self.tmp_dir)
      # The target file should still exist.
      self.assertTrue(os.path.isfile(external_temp_file))
    finally:
      shutil.rmtree(external_temp_file, ignore_errors=True)

  def testOsWalk(self):
    paths_nofollow_links = _GetAllPaths(self.tmp_dir, followlinks=False)
    paths_follow_links = _GetAllPaths(self.tmp_dir, followlinks=True)
    print('\nOsWalk Follow links:')
    for path in paths_follow_links:
      print('  ' + path + ' (' + _PathTypeToString(path) + ')')
    print('\nOsWalk No-Follow links:')
    for path in paths_nofollow_links:
      print('  ' + path + ' (' + _PathTypeToString(path) + ')')
    print('')
    self.assertIn(self.link_dir, paths_nofollow_links)
    self.assertIn(self.link_dir, paths_follow_links)
    self.assertIn(
        os.path.join(self.link_dir, _TARGET_FILENAME), paths_follow_links)
    self.assertNotIn(
        os.path.join(self.link_dir, _TARGET_FILENAME), paths_nofollow_links)


def _MakeDirs(path):
  if not os.path.isdir(path):
    os.makedirs(path)


def _PathTypeToString(path):
  if IsSymLink(path):
    return 'link'
  if os.path.isdir(path):
    return 'dir'
  return 'file'


def _GetAllPaths(start_dir, followlinks):
  paths = []
  for root, dirs, files in OsWalk(start_dir, followlinks=followlinks):
    for name in files:
      path = os.path.join(root, name)
      paths.append(path)
    for name in dirs:
      path = os.path.join(root, name)
      paths.append(path)
  return paths


def _IsSamePath(p1, p2):
  if not p1:
    p1 = None
  if not p2:
    p2 = None
  if p1 == p2:
    return True
  if (not p1) or (not p2):
    return False
  p1 = os.path.abspath(os.path.normpath(p1))
  p2 = os.path.abspath(os.path.normpath(p2))
  if p1 == p2:
    return True
  try:
    return os.stat(p1) == os.stat(p2)
  except Exception:  # pylint: disable=broad-except
    return False


if __name__ == '__main__':
  util.SetupDefaultLoggingConfig()
  unittest.main(verbosity=2)
