1/*
2 * Copyright (c) 2014, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "core/dom/Document.h"
33
34#include "core/html/HTMLHeadElement.h"
35#include "core/html/HTMLLinkElement.h"
36#include "core/testing/DummyPageHolder.h"
37#include "platform/heap/Handle.h"
38#include <gmock/gmock.h>
39#include <gtest/gtest.h>
40
41using namespace blink;
42
43namespace {
44
45class DocumentTest : public ::testing::Test {
46protected:
47    virtual void SetUp() OVERRIDE;
48
49#if ENABLE(OILPAN)
50    virtual void TearDown() OVERRIDE
51    {
52        Heap::collectAllGarbage();
53    }
54#endif
55
56    Document& document() const { return m_dummyPageHolder->document(); }
57    Page& page() const { return m_dummyPageHolder->page(); }
58
59private:
60    OwnPtr<DummyPageHolder> m_dummyPageHolder;
61};
62
63void DocumentTest::SetUp()
64{
65    m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600));
66}
67
68class MockDocumentVisibilityObserver
69    : public NoBaseWillBeGarbageCollectedFinalized<MockDocumentVisibilityObserver>
70    , public DocumentVisibilityObserver {
71    WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(MockDocumentVisibilityObserver);
72public:
73    static PassOwnPtrWillBeRawPtr<MockDocumentVisibilityObserver> create(Document& document)
74    {
75        return adoptPtrWillBeNoop(new MockDocumentVisibilityObserver(document));
76    }
77
78    virtual void trace(Visitor*) { }
79
80    MOCK_METHOD1(didChangeVisibilityState, void(PageVisibilityState));
81
82private:
83    MockDocumentVisibilityObserver(Document& document) : DocumentVisibilityObserver(document) { }
84};
85
86TEST_F(DocumentTest, VisibilityOberver)
87{
88    page().setVisibilityState(PageVisibilityStateVisible, true); // initial state
89    OwnPtrWillBeRawPtr<MockDocumentVisibilityObserver> observer1 = MockDocumentVisibilityObserver::create(document());
90
91    {
92        OwnPtrWillBeRawPtr<MockDocumentVisibilityObserver> observer2 = MockDocumentVisibilityObserver::create(document());
93        EXPECT_CALL(*observer1, didChangeVisibilityState(PageVisibilityStateHidden)).Times(0);
94        EXPECT_CALL(*observer1, didChangeVisibilityState(PageVisibilityStateVisible)).Times(0);
95        EXPECT_CALL(*observer2, didChangeVisibilityState(PageVisibilityStateHidden)).Times(0);
96        EXPECT_CALL(*observer2, didChangeVisibilityState(PageVisibilityStateVisible)).Times(0);
97        ::testing::Mock::VerifyAndClearExpectations(observer1.get());
98        ::testing::Mock::VerifyAndClearExpectations(observer2.get());
99
100        EXPECT_CALL(*observer1, didChangeVisibilityState(PageVisibilityStateHidden)).Times(1);
101        EXPECT_CALL(*observer1, didChangeVisibilityState(PageVisibilityStateVisible)).Times(0);
102        EXPECT_CALL(*observer2, didChangeVisibilityState(PageVisibilityStateHidden)).Times(1);
103        EXPECT_CALL(*observer2, didChangeVisibilityState(PageVisibilityStateVisible)).Times(0);
104        page().setVisibilityState(PageVisibilityStateHidden, false);
105        ::testing::Mock::VerifyAndClearExpectations(observer1.get());
106        ::testing::Mock::VerifyAndClearExpectations(observer2.get());
107
108        EXPECT_CALL(*observer1, didChangeVisibilityState(PageVisibilityStateHidden)).Times(0);
109        EXPECT_CALL(*observer1, didChangeVisibilityState(PageVisibilityStateVisible)).Times(0);
110        EXPECT_CALL(*observer2, didChangeVisibilityState(PageVisibilityStateHidden)).Times(0);
111        EXPECT_CALL(*observer2, didChangeVisibilityState(PageVisibilityStateVisible)).Times(0);
112        page().setVisibilityState(PageVisibilityStateHidden, false);
113        ::testing::Mock::VerifyAndClearExpectations(observer1.get());
114        ::testing::Mock::VerifyAndClearExpectations(observer2.get());
115
116        EXPECT_CALL(*observer1, didChangeVisibilityState(PageVisibilityStateHidden)).Times(0);
117        EXPECT_CALL(*observer1, didChangeVisibilityState(PageVisibilityStateVisible)).Times(1);
118        EXPECT_CALL(*observer2, didChangeVisibilityState(PageVisibilityStateHidden)).Times(0);
119        EXPECT_CALL(*observer2, didChangeVisibilityState(PageVisibilityStateVisible)).Times(0);
120        OwnPtr<DummyPageHolder> alternatePage = DummyPageHolder::create(IntSize(800, 600));
121        Document& alternateDocument = alternatePage->document();
122        observer2->setObservedDocument(alternateDocument);
123        page().setVisibilityState(PageVisibilityStateVisible, false);
124        ::testing::Mock::VerifyAndClearExpectations(observer1.get());
125        ::testing::Mock::VerifyAndClearExpectations(observer2.get());
126
127        EXPECT_CALL(*observer1, didChangeVisibilityState(PageVisibilityStateHidden)).Times(1);
128        EXPECT_CALL(*observer1, didChangeVisibilityState(PageVisibilityStateVisible)).Times(0);
129        EXPECT_CALL(*observer2, didChangeVisibilityState(PageVisibilityStateHidden)).Times(1);
130        EXPECT_CALL(*observer2, didChangeVisibilityState(PageVisibilityStateVisible)).Times(0);
131        observer2->setObservedDocument(document());
132        page().setVisibilityState(PageVisibilityStateHidden, false);
133        ::testing::Mock::VerifyAndClearExpectations(observer1.get());
134        ::testing::Mock::VerifyAndClearExpectations(observer2.get());
135    }
136
137    // observer2 destroyed
138    EXPECT_CALL(*observer1, didChangeVisibilityState(PageVisibilityStateHidden)).Times(0);
139    EXPECT_CALL(*observer1, didChangeVisibilityState(PageVisibilityStateVisible)).Times(1);
140    page().setVisibilityState(PageVisibilityStateVisible, false);
141}
142
143// This test checks that Documunt::linkManifest() returns a value conform to the specification.
144TEST_F(DocumentTest, LinkManifest)
145{
146    // Test the default result.
147    EXPECT_EQ(0, document().linkManifest());
148
149    // Check that we use the first manifest with <link rel=manifest>
150    RefPtrWillBeRawPtr<HTMLLinkElement> link = HTMLLinkElement::create(document(), false);
151    link->setAttribute(blink::HTMLNames::relAttr, "manifest");
152    link->setAttribute(blink::HTMLNames::hrefAttr, "foo.json");
153    document().head()->appendChild(link);
154    EXPECT_EQ(link, document().linkManifest());
155
156    RefPtrWillBeRawPtr<HTMLLinkElement> link2 = HTMLLinkElement::create(document(), false);
157    link2->setAttribute(blink::HTMLNames::relAttr, "manifest");
158    link2->setAttribute(blink::HTMLNames::hrefAttr, "bar.json");
159    document().head()->insertBefore(link2, link.get());
160    EXPECT_EQ(link2, document().linkManifest());
161    document().head()->appendChild(link2);
162    EXPECT_EQ(link, document().linkManifest());
163
164    // Check that crazy URLs are accepted.
165    link->setAttribute(blink::HTMLNames::hrefAttr, "http:foo.json");
166    EXPECT_EQ(link, document().linkManifest());
167
168    // Check that empty URLs are accepted.
169    link->setAttribute(blink::HTMLNames::hrefAttr, "");
170    EXPECT_EQ(link, document().linkManifest());
171
172    // Check that URLs from different origins are accepted.
173    link->setAttribute(blink::HTMLNames::hrefAttr, "http://example.org/manifest.json");
174    EXPECT_EQ(link, document().linkManifest());
175    link->setAttribute(blink::HTMLNames::hrefAttr, "http://foo.example.org/manifest.json");
176    EXPECT_EQ(link, document().linkManifest());
177    link->setAttribute(blink::HTMLNames::hrefAttr, "http://foo.bar/manifest.json");
178    EXPECT_EQ(link, document().linkManifest());
179
180    // More than one token in @rel is accepted.
181    link->setAttribute(blink::HTMLNames::relAttr, "foo bar manifest");
182    EXPECT_EQ(link, document().linkManifest());
183
184    // Such as spaces around the token.
185    link->setAttribute(blink::HTMLNames::relAttr, " manifest ");
186    EXPECT_EQ(link, document().linkManifest());
187
188    // Check that rel=manifest actually matters.
189    link->setAttribute(blink::HTMLNames::relAttr, "");
190    EXPECT_EQ(link2, document().linkManifest());
191    link->setAttribute(blink::HTMLNames::relAttr, "manifest");
192
193    // Check that link outside of the <head> are ignored.
194    document().head()->removeChild(link.get(), ASSERT_NO_EXCEPTION);
195    document().head()->removeChild(link2.get(), ASSERT_NO_EXCEPTION);
196    EXPECT_EQ(0, document().linkManifest());
197    document().body()->appendChild(link);
198    EXPECT_EQ(0, document().linkManifest());
199    document().head()->appendChild(link);
200    document().head()->appendChild(link2);
201
202    // Check that some attribute values do not have an effect.
203    link->setAttribute(blink::HTMLNames::crossoriginAttr, "use-credentials");
204    EXPECT_EQ(link, document().linkManifest());
205    link->setAttribute(blink::HTMLNames::hreflangAttr, "klingon");
206    EXPECT_EQ(link, document().linkManifest());
207    link->setAttribute(blink::HTMLNames::typeAttr, "image/gif");
208    EXPECT_EQ(link, document().linkManifest());
209    link->setAttribute(blink::HTMLNames::sizesAttr, "16x16");
210    EXPECT_EQ(link, document().linkManifest());
211    link->setAttribute(blink::HTMLNames::mediaAttr, "print");
212    EXPECT_EQ(link, document().linkManifest());
213}
214
215} // unnamed namespace
216