/*
 * Copyright 2016 Google Inc. 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.
 */

#include "cobalt/cssom/css_computed_style_data.h"
#include "cobalt/cssom/css_computed_style_declaration.h"
#include "cobalt/cssom/keyword_value.h"
#include "cobalt/cssom/length_value.h"
#include "cobalt/cssom/property_definitions.h"
#include "cobalt/dom/dom_exception.h"
#include "cobalt/script/exception_state.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace cobalt {
namespace cssom {

using ::testing::_;
using ::testing::Return;

namespace {
class FakeExceptionState : public script::ExceptionState {
 public:
  void SetException(
      const scoped_refptr<script::ScriptException>& exception) OVERRIDE {
    dom_exception_ = make_scoped_refptr(
        base::polymorphic_downcast<dom::DOMException*>(exception.get()));
  }
  void SetSimpleException(script::MessageType /*message_type*/, ...) OVERRIDE {
    // no-op
  }
  dom::DOMException::ExceptionCode GetExceptionCode() {
    return dom_exception_ ? static_cast<dom::DOMException::ExceptionCode>(
                                dom_exception_->code())
                          : dom::DOMException::kNone;
  }

 private:
  scoped_refptr<dom::DOMException> dom_exception_;
};
}  // namespace

TEST(CSSComputedStyleDeclarationTest, CSSTextSetterRaisesException) {
  scoped_refptr<CSSComputedStyleDeclaration> style =
      new CSSComputedStyleDeclaration();
  FakeExceptionState exception_state;

  const std::string css_text = "font-size: 100px; color: #0047ab;";
  style->set_css_text(css_text, &exception_state);
  EXPECT_EQ(dom::DOMException::kInvalidAccessErr,
            exception_state.GetExceptionCode());
}

TEST(CSSComputedStyleDeclarationTest, DISABLED_CSSTextGetter) {
  scoped_refptr<LengthValue> background_size =
      new LengthValue(100, kPixelsUnit);
  scoped_refptr<LengthValue> bottom = new LengthValue(16, kPixelsUnit);

  scoped_refptr<CSSComputedStyleData> style_data = new CSSComputedStyleData();
  style_data->SetPropertyValue(kBackgroundSizeProperty, background_size);
  style_data->SetPropertyValue(kBottomProperty, bottom);

  scoped_refptr<CSSComputedStyleDeclaration> style =
      new CSSComputedStyleDeclaration();
  style->SetData(style_data);
  EXPECT_EQ(style->css_text(NULL), "background-size: 100px; bottom: 16px;");
}

TEST(CSSComputedStyleDeclarationTest, PropertyValueSetterRaisesException) {
  scoped_refptr<CSSComputedStyleDeclaration> style =
      new CSSComputedStyleDeclaration();
  const std::string background = "rgba(0, 0, 0, .8)";
  FakeExceptionState exception_state;

  style->SetPropertyValue(GetPropertyName(kBackgroundProperty), background,
                          &exception_state);
  EXPECT_EQ(dom::DOMException::kInvalidAccessErr,
            exception_state.GetExceptionCode());
}

TEST(CSSComputedStyleDeclarationTest,
     PropertySetterWithTwoValuesRaisesException) {
  scoped_refptr<CSSComputedStyleDeclaration> style =
      new CSSComputedStyleDeclaration();
  const std::string background = "rgba(0, 0, 0, .8)";
  FakeExceptionState exception_state;

  style->SetProperty(GetPropertyName(kBackgroundProperty), background,
                     &exception_state);
  EXPECT_EQ(dom::DOMException::kInvalidAccessErr,
            exception_state.GetExceptionCode());
}

TEST(CSSComputedStyleDeclarationTest,
     PropertySetterWithThreeValuesRaisesException) {
  scoped_refptr<CSSComputedStyleDeclaration> style =
      new CSSComputedStyleDeclaration();
  const std::string background = "rgba(0, 0, 0, .8)";
  FakeExceptionState exception_state;

  style->SetProperty(GetPropertyName(kBackgroundProperty), background,
                     std::string(), &exception_state);
  EXPECT_EQ(dom::DOMException::kInvalidAccessErr,
            exception_state.GetExceptionCode());
}

TEST(CSSComputedStyleDeclarationTest, RemovePropertyRaisesException) {
  scoped_refptr<CSSComputedStyleData> initial_style =
      new CSSComputedStyleData();
  initial_style->SetPropertyValue(kDisplayProperty, KeywordValue::GetInline());
  scoped_refptr<CSSComputedStyleDeclaration> style =
      new CSSComputedStyleDeclaration();
  style->SetData(initial_style);

  const std::string background = "rgba(0, 0, 0, .8)";
  FakeExceptionState exception_state;

  style->RemoveProperty(GetPropertyName(kDisplayProperty), &exception_state);
  EXPECT_EQ(dom::DOMException::kInvalidAccessErr,
            exception_state.GetExceptionCode());
}

TEST(CSSComputedStyleDeclarationTest, PropertyValueGetter) {
  scoped_refptr<CSSComputedStyleData> initial_style =
      new CSSComputedStyleData();
  initial_style->SetPropertyValue(kTextAlignProperty,
                                  KeywordValue::GetCenter());
  scoped_refptr<CSSComputedStyleDeclaration> style =
      new CSSComputedStyleDeclaration();
  style->SetData(initial_style);

  EXPECT_EQ(style->GetPropertyValue(GetPropertyName(kTextAlignProperty)),
            "center");
}

TEST(CSSComputedStyleDeclarationTest,
     UnknownDeclaredStylePropertyValueShouldBeEmpty) {
  scoped_refptr<CSSComputedStyleData> initial_style =
      new CSSComputedStyleData();
  scoped_refptr<CSSComputedStyleDeclaration> style =
      new CSSComputedStyleDeclaration();
  style->SetData(initial_style);

  EXPECT_EQ(style->GetPropertyValue("cobalt_cobalt_cobalt"), "");
}

TEST(CSSComputedStyleDeclarationTest, LengthAttributeGetterEmpty) {
  scoped_refptr<CSSComputedStyleDeclaration> style =
      new CSSComputedStyleDeclaration();

  EXPECT_EQ(style->length(), kMaxLonghandPropertyKey + 1);
}

TEST(CSSComputedStyleDeclarationTest, LengthAttributeGetterNotEmpty) {
  scoped_refptr<CSSComputedStyleData> initial_style =
      new CSSComputedStyleData();
  initial_style->SetPropertyValue(kDisplayProperty, KeywordValue::GetInline());
  initial_style->SetPropertyValue(kTextAlignProperty,
                                  KeywordValue::GetCenter());
  scoped_refptr<CSSComputedStyleDeclaration> style =
      new CSSComputedStyleDeclaration();
  style->SetData(initial_style);

  EXPECT_EQ(style->length(), kMaxLonghandPropertyKey + 1);
}

TEST(CSSComputedStyleDeclarationTest, ItemGetterEmpty) {
  scoped_refptr<CSSComputedStyleDeclaration> style =
      new CSSComputedStyleDeclaration();

  // Computed styles are never actually empty.
  EXPECT_TRUE(style->Item(0));
}

TEST(CSSComputedStyleDeclarationTest, ItemGetterNotEmpty) {
  scoped_refptr<CSSComputedStyleData> initial_style =
      new CSSComputedStyleData();
  initial_style->SetPropertyValue(kDisplayProperty, KeywordValue::GetInline());
  initial_style->SetPropertyValue(kTextAlignProperty,
                                  KeywordValue::GetCenter());
  scoped_refptr<CSSComputedStyleDeclaration> style =
      new CSSComputedStyleDeclaration();
  style->SetData(initial_style);

  int property_count = 0;
  for (unsigned int key = 0; key <= kMaxLonghandPropertyKey; ++key) {
    // The order is not important, as long as all properties are represented.
    EXPECT_TRUE(style->Item(key));
    if (style->Item(key).value() == GetPropertyName(kDisplayProperty)) {
      ++property_count;
    }
    if (style->Item(key).value() == GetPropertyName(kTextAlignProperty)) {
      ++property_count;
    }
  }
  EXPECT_EQ(property_count, 2);
}

}  // namespace cssom
}  // namespace cobalt
