// 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_(&kAsyncLoopConfigNoAttachToCurrentThread) {
    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::OpenFlags::RIGHT_READABLE | fuchsia::io::OpenFlags::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::OpenFlags::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::OpenFlags::RIGHT_READABLE | fuchsia::io::OpenFlags::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::OpenFlags::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::OpenFlags::RIGHT_READABLE | fuchsia::io::OpenFlags::RIGHT_WRITABLE);
    fuchsia::io::FileSyncPtr file_ptr;
    AssertOpenPath(remote_ptr, "file1", file_ptr, fuchsia::io::OpenFlags::RIGHT_READABLE);
    AssertRead(file_ptr, 1024, "file1");
  }
}

}  // namespace
