// Copyright 2014 The Bazel 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.
package com.google.devtools.build.lib.vfs;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;

import com.google.common.collect.Lists;
import com.google.common.testing.EqualsTester;
import com.google.devtools.build.lib.testutil.TestUtils;
import com.google.devtools.build.lib.vfs.util.FileSystems;
import com.google.devtools.build.lib.vfs.util.TestUnixGlobPathDiscriminator;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Tests for {@link Path} in combination with the native file system for the current platform. */
@RunWith(JUnit4.class)
public class NativePathTest {

  private FileSystem fs;
  private File aDirectory;
  private File aFile;
  private File anotherFile;
  private File tmpDir;

  protected FileSystem getNativeFileSystem() {
    return FileSystems.getNativeFileSystem();
  }

  @Before
  public final void createFiles() throws Exception  {
    fs = getNativeFileSystem();
    tmpDir = new File(TestUtils.tmpDir(), "tmpDir");
    tmpDir.mkdirs();
    aDirectory = new File(tmpDir, "a_directory");
    aDirectory.mkdirs();
    aFile = new File(tmpDir, "a_file");
    new FileOutputStream(aFile).close();
    anotherFile = new File(aDirectory, "another_file.txt");
    new FileOutputStream(anotherFile).close();
  }

  @Test
  public void testExists() {
    assertThat(fs.getPath(aDirectory.getPath()).exists()).isTrue();
    assertThat(fs.getPath(aFile.getPath()).exists()).isTrue();
    assertThat(fs.getPath("/does/not/exist").exists()).isFalse();
  }

  @Test
  public void testDirectoryEntriesForDirectory() throws IOException {
    assertThat(fs.getPath(tmpDir.getPath()).getDirectoryEntries()).containsExactly(
      fs.getPath(tmpDir.getPath() + "/a_file"),
      fs.getPath(tmpDir.getPath() + "/a_directory"));

  }

  @Test
  public void testDirectoryEntriesForFileThrowsException() {
    assertThrows(IOException.class, () -> fs.getPath(aFile.getPath()).getDirectoryEntries());
  }

  @Test
  public void testIsFileIsTrueForFile() {
    assertThat(fs.getPath(aFile.getPath()).isFile()).isTrue();
  }

  @Test
  public void testIsFileIsFalseForDirectory() {
    assertThat(fs.getPath(aDirectory.getPath()).isFile()).isFalse();
  }

  @Test
  public void testBaseName() {
    assertThat(fs.getPath("/foo/base").getBaseName()).isEqualTo("base");
  }

  @Test
  public void testBaseNameRunsAfterDotDotInterpretation() {
    assertThat(fs.getPath("/base/foo/..").getBaseName()).isEqualTo("base");
  }

  @Test
  public void testIsDirectory() {
    assertThat(fs.getPath(aDirectory.getPath()).isDirectory()).isTrue();
    assertThat(fs.getPath(aFile.getPath()).isDirectory()).isFalse();
    assertThat(fs.getPath("/does/not/exist").isDirectory()).isFalse();
  }

  @Test
  public void testListNonExistingDirectoryThrowsException() {
    assertThrows(IOException.class, () -> fs.getPath("/does/not/exist").getDirectoryEntries());
  }

  private void assertPathSet(Collection<Path> actual, String... expected) {
    List<String> actualStrings = Lists.newArrayListWithCapacity(actual.size());

    for (Path path : actual) {
      actualStrings.add(path.getPathString());
    }

    assertThat(actualStrings).containsExactlyElementsIn(Arrays.asList(expected));
  }

  @Test
  public void testGlob() throws Exception {
    Collection<Path> textFiles = UnixGlob.forPath(fs.getPath(tmpDir.getPath()))
        .addPattern("*/*.txt")
        .globInterruptible();
    assertThat(textFiles).hasSize(1);
    Path onlyFile = textFiles.iterator().next();
    assertThat(onlyFile).isEqualTo(fs.getPath(anotherFile.getPath()));

    Collection<Path> onlyFiles =
        UnixGlob.forPath(fs.getPath(tmpDir.getPath()))
            .addPattern("*")
            .setPathDiscriminator(
                new TestUnixGlobPathDiscriminator(p -> true, (p, isDir) -> !isDir))
            .globInterruptible();
    assertPathSet(onlyFiles, aFile.getPath());

    Collection<Path> directoriesToo =
        UnixGlob.forPath(fs.getPath(tmpDir.getPath()))
            .addPattern("*")
            .setPathDiscriminator(new TestUnixGlobPathDiscriminator(p -> true, (p, isDir) -> true))
            .globInterruptible();
    assertPathSet(directoriesToo, aFile.getPath(), aDirectory.getPath());
  }

  @Test
  public void testGetRelative() {
    Path relative = fs.getPath("/foo").getChild("bar");
    Path expected = fs.getPath("/foo/bar");
    assertThat(relative).isEqualTo(expected);
  }

  @Test
  public void testEqualsAndHash() {
    Path path = fs.getPath("/foo/bar");
    Path equalPath = fs.getPath("/foo/bar");
    Path differentPath = fs.getPath("/foo/bar/baz");
    Object differentType = new Object();

    new EqualsTester().addEqualityGroup(path, equalPath).testEquals();
    assertThat(path.equals(differentPath)).isFalse();
    assertThat(path.equals(differentType)).isFalse();
  }

  @Test
  public void testLatin1ReadAndWrite() throws IOException {
    char[] allLatin1Chars = new char[256];
    for (int i = 0; i < 256; i++) {
      allLatin1Chars[i] = (char) i;
    }
    Path path = fs.getPath(aFile.getPath());
    String latin1String = new String(allLatin1Chars);
    FileSystemUtils.writeContentAsLatin1(path, latin1String);
    String fileContent = new String(FileSystemUtils.readContentAsLatin1(path));
    assertThat(latin1String).isEqualTo(fileContent);
  }

  /**
   * Verify that the encoding implemented by {@link
   * com.google.devtools.build.lib.vfs.FileSystemUtils#writeContentAsLatin1(Path, String)} really is
   * 8859-1 (latin1).
   */
  @Test
  public void testVerifyLatin1() throws IOException {
    char[] allLatin1Chars = new char[256];
    for( int i = 0; i < 256; i++) {
      allLatin1Chars[i] = (char)i;
    }
    Path path = fs.getPath(aFile.getPath());
    String latin1String = new String(allLatin1Chars);
    FileSystemUtils.writeContentAsLatin1(path, latin1String);
    byte[] bytes = FileSystemUtils.readContent(path);
    assertThat(latin1String).isEqualTo(new String(bytes, "ISO-8859-1"));
  }

  @Test
  public void testBytesReadAndWrite() throws IOException {
    byte[] bytes = new byte[] { (byte) 0xdeadbeef, (byte) 0xdeadbeef>>8,
                                (byte) 0xdeadbeef>>16, (byte) 0xdeadbeef>>24 };
    Path path = fs.getPath(aFile.getPath());
    FileSystemUtils.writeContent(path, bytes);
    byte[] content = FileSystemUtils.readContent(path);
    assertThat(content).hasLength(bytes.length);
    for (int i = 0; i < bytes.length; i++) {
      assertThat(content[i]).isEqualTo(bytes[i]);
    }
  }

  @Test
  public void testInputOutputStreams() throws IOException {
    Path path = fs.getPath(aFile.getPath());
    try (OutputStream out = path.getOutputStream()) {
      for (int i = 0; i < 256; i++) {
        out.write(i);
      }
    }
    try (InputStream in = path.getInputStream()) {
      for (int i = 0; i < 256; i++) {
        assertThat(in.read()).isEqualTo(i);
      }
      assertThat(in.read()).isEqualTo(-1);
    }
  }
}
