// 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.fail;

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 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() {
    try {
      fs.getPath(aFile.getPath()).getDirectoryEntries();
      fail("No exception thrown.");
    } catch (IOException x) {
      // The expected result.
    }
  }

  @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() {
    try {
      fs.getPath("/does/not/exist").getDirectoryEntries();
      fail("No exception thrown.");
    } catch (IOException ex) {
      // success!
    }
  }

  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("*")
        .setExcludeDirectories(true)
        .globInterruptible();
    assertPathSet(onlyFiles, aFile.getPath());

    Collection<Path> directoriesToo =
        UnixGlob.forPath(fs.getPath(tmpDir.getPath()))
        .addPattern("*")
        .setExcludeDirectories(false)
        .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);
    }
  }
}
