1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "config.h"
6#include "core/animation/EffectInput.h"
7
8#include "bindings/core/v8/Dictionary.h"
9#include "core/animation/AnimationTestHelper.h"
10#include "core/animation/KeyframeEffectModel.h"
11#include "core/dom/Document.h"
12#include "core/dom/Element.h"
13#include <gtest/gtest.h>
14#include <v8.h>
15
16using namespace blink;
17
18namespace {
19
20class AnimationEffectInputTest : public ::testing::Test {
21protected:
22    AnimationEffectInputTest()
23        : document(Document::create())
24        , element(document->createElement("foo", ASSERT_NO_EXCEPTION))
25        , m_isolate(v8::Isolate::GetCurrent())
26        , m_scope(m_isolate)
27    {
28    }
29
30    RefPtrWillBePersistent<Document> document;
31    RefPtrWillBePersistent<Element> element;
32    TrackExceptionState exceptionState;
33    v8::Isolate* m_isolate;
34
35private:
36    V8TestingScope m_scope;
37};
38
39TEST_F(AnimationEffectInputTest, SortedOffsets)
40{
41    Vector<Dictionary> jsKeyframes;
42    v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
43    v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
44
45    setV8ObjectPropertyAsString(keyframe1, "width", "100px");
46    setV8ObjectPropertyAsString(keyframe1, "offset", "0");
47    setV8ObjectPropertyAsString(keyframe2, "width", "0px");
48    setV8ObjectPropertyAsString(keyframe2, "offset", "1");
49
50    jsKeyframes.append(Dictionary(keyframe1, m_isolate));
51    jsKeyframes.append(Dictionary(keyframe2, m_isolate));
52
53    RefPtrWillBeRawPtr<AnimationEffect> animationEffect = EffectInput::convert(element.get(), jsKeyframes, exceptionState);
54    EXPECT_FALSE(exceptionState.hadException());
55    const KeyframeEffectModelBase& keyframeEffect = *toKeyframeEffectModelBase(animationEffect.get());
56    EXPECT_EQ(1.0, keyframeEffect.getFrames()[1]->offset());
57}
58
59TEST_F(AnimationEffectInputTest, UnsortedOffsets)
60{
61    Vector<Dictionary> jsKeyframes;
62    v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
63    v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
64
65    setV8ObjectPropertyAsString(keyframe1, "width", "0px");
66    setV8ObjectPropertyAsString(keyframe1, "offset", "1");
67    setV8ObjectPropertyAsString(keyframe2, "width", "100px");
68    setV8ObjectPropertyAsString(keyframe2, "offset", "0");
69
70    jsKeyframes.append(Dictionary(keyframe1, m_isolate));
71    jsKeyframes.append(Dictionary(keyframe2, m_isolate));
72
73    EffectInput::convert(element.get(), jsKeyframes, exceptionState);
74    EXPECT_TRUE(exceptionState.hadException());
75    EXPECT_EQ(InvalidModificationError, exceptionState.code());
76}
77
78TEST_F(AnimationEffectInputTest, LooslySorted)
79{
80    Vector<Dictionary> jsKeyframes;
81    v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
82    v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
83    v8::Handle<v8::Object> keyframe3 = v8::Object::New(m_isolate);
84
85    setV8ObjectPropertyAsString(keyframe1, "width", "100px");
86    setV8ObjectPropertyAsString(keyframe1, "offset", "0");
87    setV8ObjectPropertyAsString(keyframe2, "width", "200px");
88    setV8ObjectPropertyAsString(keyframe3, "width", "0px");
89    setV8ObjectPropertyAsString(keyframe3, "offset", "1");
90
91    jsKeyframes.append(Dictionary(keyframe1, m_isolate));
92    jsKeyframes.append(Dictionary(keyframe2, m_isolate));
93    jsKeyframes.append(Dictionary(keyframe3, m_isolate));
94
95    RefPtrWillBeRawPtr<AnimationEffect> animationEffect = EffectInput::convert(element.get(), jsKeyframes, exceptionState);
96    EXPECT_FALSE(exceptionState.hadException());
97    const KeyframeEffectModelBase& keyframeEffect = *toKeyframeEffectModelBase(animationEffect.get());
98    EXPECT_EQ(1, keyframeEffect.getFrames()[2]->offset());
99}
100
101TEST_F(AnimationEffectInputTest, OutOfOrderWithNullOffsets)
102{
103    Vector<Dictionary> jsKeyframes;
104    v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
105    v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
106    v8::Handle<v8::Object> keyframe3 = v8::Object::New(m_isolate);
107    v8::Handle<v8::Object> keyframe4 = v8::Object::New(m_isolate);
108
109    setV8ObjectPropertyAsString(keyframe1, "height", "100px");
110    setV8ObjectPropertyAsString(keyframe1, "offset", "0.5");
111    setV8ObjectPropertyAsString(keyframe2, "height", "150px");
112    setV8ObjectPropertyAsString(keyframe3, "height", "200px");
113    setV8ObjectPropertyAsString(keyframe3, "offset", "0");
114    setV8ObjectPropertyAsString(keyframe4, "height", "300px");
115    setV8ObjectPropertyAsString(keyframe4, "offset", "1");
116
117    jsKeyframes.append(Dictionary(keyframe1, m_isolate));
118    jsKeyframes.append(Dictionary(keyframe2, m_isolate));
119    jsKeyframes.append(Dictionary(keyframe3, m_isolate));
120    jsKeyframes.append(Dictionary(keyframe4, m_isolate));
121
122    EffectInput::convert(element.get(), jsKeyframes, exceptionState);
123    EXPECT_TRUE(exceptionState.hadException());
124}
125
126TEST_F(AnimationEffectInputTest, Invalid)
127{
128    // Not loosely sorted by offset, and there exists a keyframe with null offset.
129    Vector<Dictionary> jsKeyframes;
130    v8::Handle<v8::Object> keyframe1 = v8::Object::New(m_isolate);
131    v8::Handle<v8::Object> keyframe2 = v8::Object::New(m_isolate);
132    v8::Handle<v8::Object> keyframe3 = v8::Object::New(m_isolate);
133
134    setV8ObjectPropertyAsString(keyframe1, "width", "0px");
135    setV8ObjectPropertyAsString(keyframe1, "offset", "1");
136    setV8ObjectPropertyAsString(keyframe2, "width", "200px");
137    setV8ObjectPropertyAsString(keyframe3, "width", "100px");
138    setV8ObjectPropertyAsString(keyframe3, "offset", "0");
139
140    jsKeyframes.append(Dictionary(keyframe1, m_isolate));
141    jsKeyframes.append(Dictionary(keyframe2, m_isolate));
142    jsKeyframes.append(Dictionary(keyframe3, m_isolate));
143
144    EffectInput::convert(element.get(), jsKeyframes, exceptionState);
145    EXPECT_TRUE(exceptionState.hadException());
146    EXPECT_EQ(InvalidModificationError, exceptionState.code());
147}
148
149}
150