// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/platform/fonts/small_caps_iterator.h"

#include "testing/gtest/include/gtest/gtest.h"

#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"

namespace blink {

struct SmallCapsTestRun {
  const char* const text;
  SmallCapsIterator::SmallCapsBehavior code;
};

struct SmallCapsExpectedRun {
  unsigned limit;
  SmallCapsIterator::SmallCapsBehavior small_caps_behavior;

  SmallCapsExpectedRun(
      unsigned the_limit,
      SmallCapsIterator::SmallCapsBehavior the_small_caps_behavior)
      : limit(the_limit), small_caps_behavior(the_small_caps_behavior) {}
};

class SmallCapsIteratorTest : public testing::Test {
 protected:
  void CheckRuns(const Vector<SmallCapsTestRun>& runs) {
    StringBuilder text;
    text.Ensure16Bit();
    Vector<SmallCapsExpectedRun> expect;
    for (auto& run : runs) {
      text.Append(String::FromUtf8(run.text));
      expect.push_back(SmallCapsExpectedRun(text.length(), run.code));
    }
    SmallCapsIterator small_caps_iterator(text.Span16());
    VerifyRuns(&small_caps_iterator, expect);
  }

  void VerifyRuns(SmallCapsIterator* small_caps_iterator,
                  const Vector<SmallCapsExpectedRun>& expect) {
    unsigned limit;
    SmallCapsIterator::SmallCapsBehavior small_caps_behavior;
    wtf_size_t run_count = 0;
    while (small_caps_iterator->Consume(&limit, &small_caps_behavior)) {
      ASSERT_LT(run_count, expect.size());
      ASSERT_EQ(expect[run_count].limit, limit);
      ASSERT_EQ(expect[run_count].small_caps_behavior, small_caps_behavior);
      ++run_count;
    }
    ASSERT_EQ(expect.size(), run_count);
  }
};

#define CHECK_SMALL_CAPS_RUN(...)              \
  Vector<SmallCapsTestRun> runs = __VA_ARGS__; \
  CheckRuns(runs);

TEST_F(SmallCapsIteratorTest, Empty) {
  String empty(g_empty_string16_bit);
  SmallCapsIterator small_caps_iterator(empty.Span16());
  unsigned limit = 0;
  SmallCapsIterator::SmallCapsBehavior small_caps_behavior =
      SmallCapsIterator::kSmallCapsInvalid;
  DCHECK(!small_caps_iterator.Consume(&limit, &small_caps_behavior));
  ASSERT_EQ(limit, 0u);
  ASSERT_EQ(small_caps_behavior, SmallCapsIterator::kSmallCapsInvalid);
}

TEST_F(SmallCapsIteratorTest, UppercaseA) {
  CHECK_SMALL_CAPS_RUN({{"A", SmallCapsIterator::kSmallCapsSameCase}});
}

TEST_F(SmallCapsIteratorTest, LowercaseA) {
  CHECK_SMALL_CAPS_RUN({{"a", SmallCapsIterator::kSmallCapsUppercaseNeeded}});
}

TEST_F(SmallCapsIteratorTest, UppercaseLowercaseA) {
  CHECK_SMALL_CAPS_RUN({{"A", SmallCapsIterator::kSmallCapsSameCase},
                        {"a", SmallCapsIterator::kSmallCapsUppercaseNeeded}});
}

TEST_F(SmallCapsIteratorTest, UppercasePunctuationMixed) {
  CHECK_SMALL_CAPS_RUN({{"AAA??", SmallCapsIterator::kSmallCapsSameCase}});
}

TEST_F(SmallCapsIteratorTest, LowercasePunctuationMixed) {
  CHECK_SMALL_CAPS_RUN({{"aaa", SmallCapsIterator::kSmallCapsUppercaseNeeded},
                        {"===", SmallCapsIterator::kSmallCapsSameCase}});
}

TEST_F(SmallCapsIteratorTest, LowercasePunctuationInterleaved) {
  CHECK_SMALL_CAPS_RUN({{"aaa", SmallCapsIterator::kSmallCapsUppercaseNeeded},
                        {"===", SmallCapsIterator::kSmallCapsSameCase},
                        {"bbb", SmallCapsIterator::kSmallCapsUppercaseNeeded}});
}

TEST_F(SmallCapsIteratorTest, Japanese) {
  CHECK_SMALL_CAPS_RUN({{"ほへと", SmallCapsIterator::kSmallCapsSameCase}});
}

TEST_F(SmallCapsIteratorTest, Armenian) {
  CHECK_SMALL_CAPS_RUN({{"աբգդ", SmallCapsIterator::kSmallCapsUppercaseNeeded},
                        {"ԵԶԷԸ", SmallCapsIterator::kSmallCapsSameCase}});
}

TEST_F(SmallCapsIteratorTest, CombiningCharacterSequence) {
  CHECK_SMALL_CAPS_RUN({{"èü", SmallCapsIterator::kSmallCapsUppercaseNeeded}});
}

}  // namespace blink
