// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <fuchsia/io/cpp/fidl.h>
#include <lib/fdio/vfs.h>
#include <lib/fidl/cpp/interface_request.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/vfs/cpp/pseudo_file.h>
#include <lib/vfs/cpp/remote_dir.h>
#include <lib/vfs/cpp/testing/dir_test_util.h>

#include <memory>

namespace {

class RemoteDirConnection : public vfs_tests::DirConnection {
 public:
  RemoteDirConnection() : loop_(&kAsyncLoopConfigNoAttachToThread) {
    AddFileToPseudoDir("file1");
    AddFileToPseudoDir("file2");
    AddFileToPseudoDir("file3");
    loop_.StartThread("vfs test thread");
  }

 protected:
  vfs::internal::Directory* GetDirectoryNode() override { return dir_.get(); }

  fuchsia::io::DirectoryPtr GetPseudoDirConnection() {
    fuchsia::io::DirectoryPtr ptr;
    pseudo_dir_.Serve(
        fuchsia::io::OPEN_RIGHT_READABLE | fuchsia::io::OPEN_RIGHT_WRITABLE,
        ptr.NewRequest().TakeChannel(), loop_.dispatcher());
    return ptr;
  }

  void ReadDir(vfs::internal::Directory* dir, std::vector<uint8_t>* dirents,
               uint64_t buffer_size = 1024) {
    fuchsia::io::DirectorySyncPtr ptr;
    dir->Serve(fuchsia::io::OPEN_RIGHT_READABLE, ptr.NewRequest().TakeChannel(),
               loop_.dispatcher());
    zx_status_t status;
    ptr->ReadDirents(buffer_size, &status, dirents);
    ASSERT_EQ(ZX_OK, status);
    ASSERT_GT(dirents->size(), 0u);
  }

  void CompareReadDirs() {
    std::vector<uint8_t> remote_dir_dirents;
    std::vector<uint8_t> pseudo_dir_dirents;
    ReadDir(&pseudo_dir_, &pseudo_dir_dirents);
    ReadDir(dir_.get(), &remote_dir_dirents);
    ASSERT_EQ(remote_dir_dirents, pseudo_dir_dirents);
  }

  vfs::PseudoDir pseudo_dir_;
  std::shared_ptr<vfs::RemoteDir> dir_;
  async::Loop loop_;

 private:
  void AddFileToPseudoDir(const std::string& name) {
    pseudo_dir_.AddEntry(
        name, std::make_unique<vfs::PseudoFile>(
                  name.length(),
                  [name](std::vector<uint8_t>* output, size_t max_file_size) {
                    output->resize(name.length());
                    std::copy(name.begin(), name.end(), output->begin());
                    return ZX_OK;
                  }));
  }
};

TEST_F(RemoteDirConnection, ConstructorWithChannel) {
  auto connection = GetPseudoDirConnection();
  dir_ = std::make_shared<vfs::RemoteDir>(connection.Unbind().TakeChannel());
  CompareReadDirs();
}

TEST_F(RemoteDirConnection, ConstructorWithInterfaceHandle) {
  auto connection = GetPseudoDirConnection();
  dir_ = std::make_shared<vfs::RemoteDir>(connection.Unbind());
  CompareReadDirs();
}

TEST_F(RemoteDirConnection, ConstructorWithDirPtr) {
  dir_ = std::make_shared<vfs::RemoteDir>(GetPseudoDirConnection());
  CompareReadDirs();
}

class RemoteDirContained : public RemoteDirConnection {
 protected:
  RemoteDirContained() {
    dir_ = std::make_shared<vfs::RemoteDir>(GetPseudoDirConnection());
    parent_pseudo_dir_.AddSharedEntry("remote_dir", dir_);
    parent_pseudo_dir_.Serve(
        fuchsia::io::OPEN_RIGHT_READABLE | fuchsia::io::OPEN_RIGHT_WRITABLE,
        ptr_.NewRequest().TakeChannel(), loop_.dispatcher());
  }

  ~RemoteDirContained() { loop_.Shutdown(); }

  vfs::PseudoDir parent_pseudo_dir_;
  fuchsia::io::DirectorySyncPtr ptr_;
};

TEST_F(RemoteDirContained, RemoteDirContainedInPseudoDir) {
  std::vector<vfs_tests::Dirent> expected = {
      vfs_tests::Dirent::DirentForDot(),
      vfs_tests::Dirent::DirentForDirectory("remote_dir")};
  AssertReadDirents(ptr_, 1024, expected);
}

TEST_F(RemoteDirContained, OpenAndReadFile) {
  fuchsia::io::FileSyncPtr file_ptr;
  std::string paths[] = {"remote_dir/file1", "remote_dir//file1",
                         "remote_dir/./file1"};
  for (auto& path : paths) {
    SCOPED_TRACE(path);
    AssertOpenPath(ptr_, path, file_ptr, fuchsia::io::OPEN_RIGHT_READABLE);
    AssertRead(file_ptr, 1024, "file1");
  }
}

TEST_F(RemoteDirContained, OpenRemoteDirAndRead) {
  std::string paths[] = {"remote_dir",    "remote_dir/",  "remote_dir/.",
                         "remote_dir/./", "remote_dir//", "remote_dir//."};
  for (auto& path : paths) {
    SCOPED_TRACE(path);
    fuchsia::io::DirectorySyncPtr remote_ptr;
    AssertOpenPath(
        ptr_, path, remote_ptr,
        fuchsia::io::OPEN_RIGHT_READABLE | fuchsia::io::OPEN_RIGHT_WRITABLE);
    fuchsia::io::FileSyncPtr file_ptr;
    AssertOpenPath(remote_ptr, "file1", file_ptr,
                   fuchsia::io::OPEN_RIGHT_READABLE);
    AssertRead(file_ptr, 1024, "file1");
  }
}

}  // namespace
