// Copyright 2017-2020 The Verible Authors.
//
// 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.

#include "common/formatting/tree_unwrapper.h"

#include <algorithm>
#include <iterator>
#include <memory>
#include <vector>

#include "absl/strings/ascii.h"
#include "absl/strings/string_view.h"
#include "common/formatting/format_token.h"
#include "common/formatting/unwrapped_line.h"
#include "common/text/concrete_syntax_leaf.h"
#include "common/text/concrete_syntax_tree.h"
#include "common/text/text_structure.h"
#include "common/text/text_structure_test_utils.h"
#include "common/text/token_info.h"
#include "common/text/token_stream_view.h"
#include "common/util/container_iterator_range.h"
#include "common/util/range.h"
#include "gtest/gtest.h"

namespace verible {

static bool KeepNonWhitespace(const TokenInfo& token) {
  const absl::string_view text(absl::StripAsciiWhitespace(token.text()));
  return !text.empty();
}

class TreeUnwrapperData {
 public:
  explicit TreeUnwrapperData(const verible::TokenSequence& tokens) {
    verible::InitTokenStreamView(tokens, &tokens_view_);
    verible::FilterTokenStreamViewInPlace(KeepNonWhitespace, &tokens_view_);

    preformatted_tokens_.reserve(tokens_view_.size());
    std::transform(tokens_view_.begin(), tokens_view_.end(),
                   std::back_inserter(preformatted_tokens_),
                   [](const TokenSequence::const_iterator iter) {
                     return PreFormatToken(&*iter);
                   });
  }

 protected:
  verible::TokenStreamView tokens_view_;
  std::vector<verible::PreFormatToken> preformatted_tokens_;
};

class FakeTreeUnwrapper : public TreeUnwrapperData, public TreeUnwrapper {
 public:
  explicit FakeTreeUnwrapper(const TextStructureView& view)
      : TreeUnwrapperData(view.TokenStream()),
        TreeUnwrapper(view, TreeUnwrapperData::preformatted_tokens_) {}

  // There are no filtered-out tokens in this fake.
  void CollectLeadingFilteredTokens() final {}
  void CollectTrailingFilteredTokens() final {}

  // Leaf visit that adds a PreFormatToken from the leaf's TokenInfo
  // to the current_unwrapped_line_
  void Visit(const verible::SyntaxTreeLeaf& leaf) final {
    CatchUpFilteredTokens();
    AddTokenToCurrentUnwrappedLine();
  }

  // Node visit that always starts a new unwrapped line
  void Visit(const SyntaxTreeNode& node) final {
    StartNewUnwrappedLine(PartitionPolicyEnum::kAlwaysExpand, &node);
    TraverseChildren(node);
  }

  void InterChildNodeHook(const SyntaxTreeNode& node) final {}

  using TreeUnwrapper::StartNewUnwrappedLine;

 protected:
  void CatchUpFilteredTokens() {
    const auto iter = CurrentFormatTokenIterator();
    SkipUnfilteredTokens(
        [=](const verible::TokenInfo& token) { return &token != iter->token; });
  }
};

// Test that no new UnwrappedLines are created when current_unwrapped_line_
// is empty.
TEST(TreeUnwrapperTest, EmptyStartNewUnwrappedLine) {
  std::unique_ptr<TextStructureView> view = MakeTextStructureViewWithNoLeaves();
  FakeTreeUnwrapper tree_unwrapper(*view);

  // const reference forces use of const method
  const auto& const_tree_unwrapper(tree_unwrapper);

  // Do not call .Unwrap() for this test.

  const auto& current = const_tree_unwrapper.CurrentUnwrappedLine();
  tree_unwrapper.StartNewUnwrappedLine(PartitionPolicyEnum::kAlwaysExpand,
                                       &*view->SyntaxTree());
  const auto& next = const_tree_unwrapper.CurrentUnwrappedLine();
  EXPECT_EQ(&current, &next);
}

// Test that StartNewUnwrappedLine properly handles current_unwrapped_line_ by
// creating new unwrapped lines at each Node and appending the
// current_unwrapped_line to UnwrappedLines.
TEST(TreeUnwrapperTest, NonEmptyUnwrap) {
  std::unique_ptr<TextStructureView> view = MakeTextStructureViewHelloWorld();
  FakeTreeUnwrapper tree_unwrapper(*view);
  EXPECT_TRUE(
      verible::BoundsEqual(tree_unwrapper.FullText(), view->Contents()));

  tree_unwrapper.Unwrap();
  const auto unwrapped_lines = tree_unwrapper.FullyPartitionedUnwrappedLines();
  ASSERT_EQ(unwrapped_lines.size(), 2);
  const UnwrappedLine& first_unwrapped_line = unwrapped_lines[0];
  const UnwrappedLine& second_unwrapped_line = unwrapped_lines[1];

  EXPECT_EQ(first_unwrapped_line.Size(), 2);
  EXPECT_EQ(second_unwrapped_line.Size(), 1);

  const auto first_range = first_unwrapped_line.TokensRange();
  const auto second_range = second_unwrapped_line.TokensRange();
  EXPECT_EQ(first_range.front().TokenEnum(), 0);
  EXPECT_EQ(first_range.back().TokenEnum(), 1);
  EXPECT_EQ(second_range.front().TokenEnum(), 3);
  EXPECT_EQ(second_range.back().TokenEnum(), 3);
}

// Test that TreeUnwrapper does not gain any UnwrappedLines after calling
// StartNewUnwrappedLine when visiting a tree with no leaves.
TEST(TreeUnwrapperTest, UnwrapNoLeaves) {
  std::unique_ptr<TextStructureView> view = MakeTextStructureViewWithNoLeaves();
  FakeTreeUnwrapper tree_unwrapper(*view);
  tree_unwrapper.Unwrap();
  const auto unwrapped_lines = tree_unwrapper.FullyPartitionedUnwrappedLines();
  EXPECT_TRUE(unwrapped_lines.empty());  // Blank line removed.
}

TEST(TreeUnwrapperTest, StreamPrinting) {
  std::unique_ptr<TextStructureView> view = MakeTextStructureViewHelloWorld();
  FakeTreeUnwrapper tree_unwrapper(*view);
  EXPECT_TRUE(
      verible::BoundsEqual(tree_unwrapper.FullText(), view->Contents()));

  tree_unwrapper.Unwrap();
  std::ostringstream stream;
  stream << tree_unwrapper;
  EXPECT_EQ(stream.str(),  //
            "[hello ,], policy: always-expand, (origin: \"hello, world\")\n"
            "[world], policy: always-expand, (origin: \"world\")\n");
}

}  // namespace verible
